OSDN Git Service

[Refactor] #3766 item_activation_dragon_breath() をItemEntity のオブジェクトメソッドへ移した
[hengbandforosx/hengbandosx.git] / src / system / item-entity.cpp
1 /*
2  * @file item-entity.cpp
3  * @brief アイテム実体とそれにまつわる判定処理群
4  * @author Hourier
5  * @date 2022/11/25
6  * @details オブジェクトの状態を変更するメソッドは道半ば
7  */
8
9 #include "system/item-entity.h"
10 #include "artifact/fixed-art-types.h"
11 #include "artifact/random-art-effects.h"
12 #include "monster-race/monster-race.h"
13 #include "object-enchant/activation-info-table.h"
14 #include "object-enchant/dragon-breaths-table.h"
15 #include "object-enchant/item-feeling.h"
16 #include "object-enchant/object-curse.h"
17 #include "object-enchant/special-object-flags.h"
18 #include "object/object-value.h"
19 #include "object/tval-types.h"
20 #include "smith/object-smith.h"
21 #include "sv-definition/sv-lite-types.h"
22 #include "sv-definition/sv-other-types.h"
23 #include "sv-definition/sv-weapon-types.h"
24 #include "system/artifact-type-definition.h"
25 #include "system/baseitem-info.h"
26 #include "system/monster-race-info.h"
27 #include "term/term-color-types.h"
28 #include "util/bit-flags-calculator.h"
29 #include "util/enum-converter.h"
30 #include "util/string-processor.h"
31 #include <sstream>
32
33 ItemEntity::ItemEntity()
34     : bi_key(BaseitemKey(ItemKindType::NONE))
35     , fixed_artifact_idx(FixedArtifactId::NONE)
36 {
37 }
38
39 /*!
40  * @brief アイテムを初期化する
41  * Wipe an object clean.
42  */
43 void ItemEntity::wipe()
44 {
45     *this = {};
46 }
47
48 /*!
49  * @brief アイテムを複製する
50  * Wipe an object clean.
51  * @param j_ptr 複製元のオブジェクトの構造体参照ポインタ
52  */
53 void ItemEntity::copy_from(const ItemEntity *j_ptr)
54 {
55     *this = *j_ptr;
56 }
57
58 /*!
59  * @brief アイテム構造体にベースアイテムを作成する
60  * @param player_ptr プレイヤーへの参照ポインタ
61  * @param bi_id 新たに作成したいベースアイテム情報のID
62  */
63 void ItemEntity::prep(short new_bi_id)
64 {
65     const auto &baseitem = baseitems_info[new_bi_id];
66     auto old_stack_idx = this->stack_idx;
67     this->wipe();
68     this->stack_idx = old_stack_idx;
69     this->bi_id = new_bi_id;
70     this->bi_key = baseitem.bi_key;
71     this->pval = baseitem.pval;
72     this->number = 1;
73     this->weight = baseitem.weight;
74     this->to_h = baseitem.to_h;
75     this->to_d = baseitem.to_d;
76     this->to_a = baseitem.to_a;
77     this->ac = baseitem.ac;
78     this->dd = baseitem.dd;
79     this->ds = baseitem.ds;
80
81     if (baseitem.act_idx > RandomArtActType::NONE) {
82         this->activation_id = baseitem.act_idx;
83     }
84
85     if (this->get_baseitem().cost <= 0) {
86         this->ident |= (IDENT_BROKEN);
87     }
88
89     if (baseitem.gen_flags.has(ItemGenerationTraitType::CURSED)) {
90         this->curse_flags.set(CurseTraitType::CURSED);
91     }
92
93     if (baseitem.gen_flags.has(ItemGenerationTraitType::HEAVY_CURSE)) {
94         this->curse_flags.set(CurseTraitType::HEAVY_CURSE);
95     }
96
97     if (baseitem.gen_flags.has(ItemGenerationTraitType::PERMA_CURSE)) {
98         this->curse_flags.set(CurseTraitType::PERMA_CURSE);
99     }
100
101     if (baseitem.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE0)) {
102         this->curse_flags.set(get_curse(0, this));
103     }
104
105     if (baseitem.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE1)) {
106         this->curse_flags.set(get_curse(1, this));
107     }
108
109     if (baseitem.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE2)) {
110         this->curse_flags.set(get_curse(2, this));
111     }
112 }
113
114 /*!
115  * @brief アイテムが武器として装備できるかどうかを返す / Check if an object is weapon (including bows)
116  * @return 武器として使えるならばtrueを返す
117  */
118 bool ItemEntity::is_weapon() const
119 {
120     return this->bi_key.is_weapon();
121 }
122
123 /*!
124  * @brief アイテムが武器や矢弾として使用できるかを返す
125  * @return 武器や矢弾として使えるならばtrueを返す
126  */
127 bool ItemEntity::is_weapon_ammo() const
128 {
129     return this->is_weapon() || this->is_ammo();
130 }
131
132 /*!
133  * @brief アイテムが武器、防具、矢弾として使用できるかを返す / Check if an object is weapon, armour or ammo
134  * @return 武器、防具、矢弾として使えるならばtrueを返す
135  */
136 bool ItemEntity::is_weapon_armour_ammo() const
137 {
138     return this->is_weapon_ammo() || this->is_protector();
139 }
140
141 /*!
142  * @brief アイテムが近接武器として装備できるかを返す / Melee weapons
143  * @return 近接武器として使えるならばtrueを返す
144  */
145 bool ItemEntity::is_melee_weapon() const
146 {
147     return this->bi_key.is_melee_weapon();
148 }
149
150 /*!
151  * @brief エッセンスの付加可能な武器や矢弾かを返す
152  * @return エッセンスの付加可能な武器か矢弾ならばtrueを返す。
153  */
154 bool ItemEntity::is_melee_ammo() const
155 {
156     return this->bi_key.is_melee_ammo();
157 }
158
159 /*!
160  * @brief アイテムが装備可能であるかを返す / Wearable including all weapon, all armour, bow, light source, amulet, and ring
161  * @return 装備可能ならばTRUEを返す
162  */
163 bool ItemEntity::is_wearable() const
164 {
165     return this->bi_key.is_wearable();
166 }
167
168 /*!
169  * @brief アイテムが装備品であるかを返す(ItemEntity::is_wearableに矢弾を含む) / Equipment including all wearable objects and ammo
170  * @return 装備品ならばtrueを返す
171  */
172 bool ItemEntity::is_equipment() const
173 {
174     return this->bi_key.is_equipement();
175 }
176
177 /*!
178  * @brief 武器匠の「武器」鑑定対象になるかを判定する。/ Hook to specify "weapon"
179  * @return 対象になるならtrueを返す。
180  */
181 bool ItemEntity::is_orthodox_melee_weapons() const
182 {
183     return this->bi_key.is_orthodox_melee_weapon();
184 }
185
186 /*!
187  * @brief 修復対象となる壊れた武器かを判定する。 / Hook to specify "broken weapon"
188  * @return 修復対象になるならTRUEを返す。
189  */
190 bool ItemEntity::is_broken_weapon() const
191 {
192     return this->bi_key.is_broken_weapon();
193 }
194
195 /*!
196  * @brief アイテムが投射可能な武器かどうかを返す。
197  * @return 投射可能な武器ならばtrue
198  */
199 bool ItemEntity::is_throwable() const
200 {
201     return this->bi_key.is_throwable();
202 }
203
204 /*!
205  * @brief アイテムがどちらの手にも装備できる武器かどうかの判定
206  * @return 左右両方の手で装備できるならばtrueを返す。
207  */
208 bool ItemEntity::is_wieldable_in_etheir_hand() const
209 {
210     return this->bi_key.is_wieldable_in_etheir_hand();
211 }
212
213 /*!
214  * @brief アイテムが強化不能武器であるかを返す / Poison needle can not be enchanted
215  * @return 強化不能ならばtrueを返す
216  */
217 bool ItemEntity::refuse_enchant_weapon() const
218 {
219     return this->bi_key == BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE);
220 }
221
222 /*!
223  * @brief アイテムが強化可能武器であるかを返す /
224  * Check if an object is weapon (including bows and ammo) and allows enchantment
225  * @return 強化可能ならばtrueを返す
226  */
227 bool ItemEntity::allow_enchant_weapon() const
228 {
229     return this->is_weapon_ammo() && !this->refuse_enchant_weapon();
230 }
231
232 /*!
233  * @brief アイテムが強化可能な近接武器であるかを返す /
234  * Check if an object is melee weapon and allows enchantment
235  * @return 強化可能な近接武器ならばtrueを返す
236  */
237 bool ItemEntity::allow_enchant_melee_weapon() const
238 {
239     return this->is_melee_weapon() && !this->refuse_enchant_weapon();
240 }
241
242 /*!
243  * @brief アイテムが両手持ち可能な武器かを返す /
244  * Check if an object is melee weapon and allows wielding with two-hands
245  * @return 両手持ち可能ならばTRUEを返す
246  */
247 bool ItemEntity::allow_two_hands_wielding() const
248 {
249     return this->is_melee_weapon() && ((this->weight > 99) || (this->bi_key.tval() == ItemKindType::POLEARM));
250 }
251
252 /*!
253  * @brief アイテムが矢弾として使用できるかどうかを返す / Check if an object is ammo
254  * @return 矢弾として使えるならばtrueを返す
255  */
256 bool ItemEntity::is_ammo() const
257 {
258     return this->bi_key.is_ammo();
259 }
260
261 /*!
262  * @brief 対象のアイテムが矢やクロスボウの矢の材料になるかを返す。/
263  * Hook to determine if an object is contertible in an arrow/bolt
264  * @return 材料にできるならtrueを返す
265  */
266 bool ItemEntity::is_convertible() const
267 {
268     const auto tval = this->bi_key.tval();
269     auto is_convertible = (tval == ItemKindType::JUNK) || (tval == ItemKindType::SKELETON);
270     is_convertible |= this->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_SKELETON);
271     return is_convertible;
272 }
273
274 bool ItemEntity::is_lance() const
275 {
276     auto is_lance = this->bi_key == BaseitemKey(ItemKindType::POLEARM, SV_LANCE);
277     is_lance |= this->bi_key == BaseitemKey(ItemKindType::POLEARM, SV_HEAVY_LANCE);
278     return is_lance;
279 }
280
281 /*!
282  * @brief アイテムが防具として装備できるかどうかを返す
283  * @return 防具として装備できるならばtrueを返す
284  */
285 bool ItemEntity::is_protector() const
286 {
287     return this->bi_key.is_protector();
288 }
289
290 /*!
291  * @brief アイテムがオーラを纏える防具かどうかを返す
292  * @return オーラを纏えるならばtrueを返す
293  */
294 bool ItemEntity::can_be_aura_protector() const
295 {
296     return this->bi_key.can_be_aura_protector();
297 }
298
299 /*!
300  * @brief アイテムがレアアイテムかどうかを返す /
301  * Rare weapons/aromors including Blade of Chaos, Dragon armors, etc.
302  * @return レアアイテムならばTRUEを返す
303  */
304 bool ItemEntity::is_rare() const
305 {
306     return this->bi_key.is_rare();
307 }
308
309 /*!
310  * @brief アイテムがエゴアイテムかどうかを返す
311  * @return エゴアイテムならばtrueを返す
312  */
313 bool ItemEntity::is_ego() const
314 {
315     return this->ego_idx != EgoType::NONE;
316 }
317
318 /*!
319  * @brief アイテムが鍛冶師のエッセンス付加済みかを返す /
320  * Check if an object is made by a smith's special ability
321  * @return エッセンス付加済みならばTRUEを返す
322  */
323 bool ItemEntity::is_smith() const
324 {
325     return Smith::object_effect(this) || Smith::object_activation(this);
326 }
327
328 /*!
329  * @brief アイテムが固定アーティファクトもしくはランダムアーティファクトであるかを返す /
330  * Check if an object is artifact
331  * @return 固定アーティファクトもしくはランダムアーティファクトならばtrueを返す
332  */
333 bool ItemEntity::is_fixed_or_random_artifact() const
334 {
335     return this->is_fixed_artifact() || this->randart_name;
336 }
337
338 /*!
339  * @brief アイテムが固定アーティファクトかを返す /
340  * Check if an object is fixed artifact
341  * @return 固定アーティファクトならばtrueを返す
342  */
343 bool ItemEntity::is_fixed_artifact() const
344 {
345     return !this->is_specific_artifact(FixedArtifactId::NONE);
346 }
347
348 /*!
349  * @brief アイテムがランダムアーティファクトかを返す /
350  * Check if an object is random artifact
351  * @return ランダムアーティファクトならばtrueを返す
352  */
353 bool ItemEntity::is_random_artifact() const
354 {
355     return this->is_fixed_or_random_artifact() && !this->is_fixed_artifact();
356 }
357
358 /*!
359  * @brief アイテムが通常のアイテム(アーティファクト、エゴ、鍛冶師エッセンス付加いずれでもない)かを返す /
360  * Check if an object is neither artifact, ego, nor 'smith' object
361  * @return 通常のアイテムならばtrueを返す
362  */
363 bool ItemEntity::is_nameless() const
364 {
365     return !this->is_fixed_or_random_artifact() && !this->is_ego() && !this->is_smith();
366 }
367
368 bool ItemEntity::is_valid() const
369 {
370     return this->bi_id != 0;
371 }
372
373 bool ItemEntity::is_broken() const
374 {
375     return any_bits(this->ident, IDENT_BROKEN);
376 }
377
378 bool ItemEntity::is_cursed() const
379 {
380     return this->curse_flags.any();
381 }
382
383 bool ItemEntity::is_held_by_monster() const
384 {
385     return this->held_m_idx != 0;
386 }
387
388 /*
389  * Determine if a given inventory item is "known"
390  * Test One -- Check for special "known" tag
391  * Test Two -- Check for "Easy Know" + "Aware"
392  */
393 bool ItemEntity::is_known() const
394 {
395     const auto &baseitem = this->get_baseitem();
396     return any_bits(this->ident, IDENT_KNOWN) || (baseitem.easy_know && baseitem.aware);
397 }
398
399 bool ItemEntity::is_fully_known() const
400 {
401     return any_bits(this->ident, IDENT_FULL_KNOWN);
402 }
403
404 /*!
405  * @brief 与えられたオブジェクトのベースアイテムが鑑定済かを返す / Determine if a given inventory item is "aware"
406  * @return 鑑定済ならtrue
407  */
408 bool ItemEntity::is_aware() const
409 {
410     return this->get_baseitem().aware;
411 }
412
413 /*
414  * Determine if a given inventory item is "tried"
415  */
416 bool ItemEntity::is_tried() const
417 {
418     return this->get_baseitem().tried;
419 }
420
421 /*!
422  * @brief アイテムが薬であるかを返す
423  * @return オブジェクトが薬ならばtrueを返す
424  */
425 bool ItemEntity::is_potion() const
426 {
427     return this->bi_key.tval() == ItemKindType::POTION;
428 }
429
430 /*!
431  * @brief アイテムをプレイヤーが読むことができるかを判定する /
432  * Hook to determine if an object is readable
433  * @return 読むことが可能ならばtrueを返す
434  */
435 bool ItemEntity::is_readable() const
436 {
437     const auto tval = this->bi_key.tval();
438     auto can_read = tval == ItemKindType::SCROLL;
439     can_read |= tval == ItemKindType::PARCHMENT;
440     can_read |= this->is_specific_artifact(FixedArtifactId::GHB);
441     can_read |= this->is_specific_artifact(FixedArtifactId::POWER);
442     return can_read;
443 }
444
445 /*!
446  * @brief アイテムがランタンの燃料になるかどうかを判定する
447  * An "item_tester_hook" for refilling lanterns
448  * @return オブジェクトがランタンの燃料になるならばTRUEを返す
449  */
450 bool ItemEntity::can_refill_lantern() const
451 {
452     const auto tval = this->bi_key.tval();
453     return (tval == ItemKindType::FLASK) || (this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN));
454 }
455
456 /*!
457  * @brief アイテムが松明に束ねられるかどうかを判定する
458  * An "item_tester_hook" for refilling torches
459  * @return オブジェクトが松明に束ねられるならばTRUEを返す
460  */
461 bool ItemEntity::can_refill_torch() const
462 {
463     return this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_TORCH);
464 }
465
466 /*!
467  * @brief 魔力充填が可能なアイテムかどうか判定する
468  * @return 魔力充填が可能ならばTRUEを返す
469  */
470 bool ItemEntity::can_recharge() const
471 {
472     return this->bi_key.can_recharge();
473 }
474
475 /*!
476  * @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを返す。 / An "item_tester_hook" for offer
477  * @return 生贄に使用可能な死体ならばTRUEを返す。
478  */
479 bool ItemEntity::is_offerable() const
480 {
481     if (this->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE)) {
482         return false;
483     }
484
485     return angband_strchr("pht", monraces_info[i2enum<MonsterRaceId>(this->pval)].d_char) != nullptr;
486 }
487
488 /*!
489  * @brief アイテムをプレイヤーが魔道具として発動できるかを判定する /
490  * Hook to determine if an object is activatable
491  * @return 魔道具として発動可能ならばTRUEを返す
492  */
493 bool ItemEntity::is_activatable() const
494 {
495     if (!this->is_known()) {
496         return false;
497     }
498
499     const auto flags = this->get_flags();
500     return flags.has(TR_ACTIVATE);
501 }
502
503 /*!
504  * @brief アイテムが燃料として使えるかを判定する
505  * @return 燃料か否か
506  */
507 bool ItemEntity::is_fuel() const
508 {
509     auto is_fuel = this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_TORCH);
510     is_fuel |= this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN);
511     is_fuel |= this->bi_key == BaseitemKey(ItemKindType::FLASK, SV_FLASK_OIL);
512     return is_fuel;
513 }
514
515 /*!
516  * @brief アイテムが魔法書かどうかを判定する
517  * @return 魔法書か否か
518  */
519 bool ItemEntity::is_spell_book() const
520 {
521     return this->bi_key.is_spell_book();
522 }
523
524 /*!
525  * @brief アイテムが同一の命中値上昇及びダメージ上昇があるかを判定する
526  * @return 同一修正か
527  * @details 鍛冶師が篭手に殺戮エッセンスを付加した場合のみこの判定に意味がある
528  */
529 bool ItemEntity::is_glove_same_temper(const ItemEntity *j_ptr) const
530 {
531     if (!this->is_smith() || !j_ptr->is_smith()) {
532         return false;
533     }
534
535     if (this->smith_hit != j_ptr->smith_hit) {
536         return true;
537     }
538
539     if (this->smith_damage != j_ptr->smith_damage) {
540         return true;
541     }
542
543     return false;
544 }
545
546 /*!
547  * @brief アイテムが「2つの~~」と重ねられるかを一般的に判定する
548  * @return 重ねられるか
549  * @details 個別のアイテムによっては別途条件があるが、それはこの関数では判定しない
550  */
551 bool ItemEntity::can_pile(const ItemEntity *j_ptr) const
552 {
553     if (this->is_known() != j_ptr->is_known()) {
554         return false;
555     }
556
557     if (this->feeling != j_ptr->feeling) {
558         return false;
559     }
560
561     if (this->to_h != j_ptr->to_h) {
562         return false;
563     }
564
565     if (this->to_d != j_ptr->to_d) {
566         return false;
567     }
568
569     if (this->to_a != j_ptr->to_a) {
570         return false;
571     }
572
573     if (this->pval != j_ptr->pval) {
574         return false;
575     }
576
577     if (this->is_fixed_or_random_artifact() || j_ptr->is_fixed_or_random_artifact()) {
578         return false;
579     }
580
581     if (this->ego_idx != j_ptr->ego_idx) {
582         return false;
583     }
584
585     if (this->timeout || j_ptr->timeout) {
586         return false;
587     }
588
589     if (this->ac != j_ptr->ac) {
590         return false;
591     }
592
593     if (this->dd != j_ptr->dd) {
594         return false;
595     }
596
597     if (this->ds != j_ptr->ds) {
598         return false;
599     }
600
601     if (Smith::object_effect(this) != Smith::object_effect(j_ptr)) {
602         return false;
603     }
604
605     if (Smith::object_activation(this) != Smith::object_activation(j_ptr)) {
606         return false;
607     }
608
609     return true;
610 }
611
612 /*
613  * @brief アイテムの色を取得する
614  * @details 未鑑定名のあるアイテム (薬等)は、未鑑定名の割り当てられた色を返す
615  * 未鑑定名のないアイテム (魔法書等)はベースアイテム定義そのままを返す
616  * その中でモンスターの死体以外は、ベースアイテムの色を返す
617  * モンスターの死体は、元モンスターの色を返す
618  * 異常アイテム (「何か」)の場合、ベースアイテム定義に基づき黒を返す
619  */
620 TERM_COLOR ItemEntity::get_color() const
621 {
622     const auto &baseitem = this->get_baseitem();
623     const auto flavor = baseitem.flavor;
624     if (flavor != 0) {
625         return baseitems_info[flavor].x_attr;
626     }
627
628     auto has_attr = !this->is_valid();
629     has_attr |= this->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE);
630     has_attr |= baseitem.x_attr != TERM_DARK;
631     if (has_attr) {
632         return baseitem.x_attr;
633     }
634
635     return monraces_info[i2enum<MonsterRaceId>(this->pval)].x_attr;
636 }
637
638 /*
639  * @brief アイテムシンボルを取得する
640  * @details 未鑑定名のないアイテム (魔法書等)はベースアイテム定義そのまま
641  * 未鑑定名のあるアイテム (薬等)は、未鑑定名の割り当てられたシンボル
642  * 以上について、設定で変更しているシンボルならばそれを、していないならば定義シンボルを返す
643  */
644 char ItemEntity::get_symbol() const
645 {
646     const auto &baseitem = this->get_baseitem();
647     const auto flavor = baseitem.flavor;
648     return flavor ? baseitems_info[flavor].x_char : baseitem.x_char;
649 }
650
651 /*!
652  * @brief アイテム価格算出のメインルーチン
653  * @return オブジェクトの判明している現価格
654  */
655 int ItemEntity::get_price() const
656 {
657     int value;
658     const auto is_worthless = this->is_broken() || this->is_cursed();
659     if (this->is_known()) {
660         if (is_worthless) {
661             return 0;
662         }
663
664         value = object_value_real(this);
665     } else {
666         if (any_bits(this->ident, IDENT_SENSE) && is_worthless) {
667             return 0;
668         }
669
670         value = this->get_baseitem_price();
671     }
672
673     if (this->discount) {
674         value -= (value * this->discount / 100L);
675     }
676
677     return value;
678 }
679
680 /*!
681  * @brief 未鑑定なベースアイテムの基本価格を返す
682  * @return オブジェクトの未鑑定価格
683  */
684 int ItemEntity::get_baseitem_price() const
685 {
686     if (this->is_aware()) {
687         return this->get_baseitem().cost;
688     }
689
690     switch (this->bi_key.tval()) {
691     case ItemKindType::FOOD:
692         return 5;
693     case ItemKindType::POTION:
694     case ItemKindType::SCROLL:
695         return 20;
696     case ItemKindType::STAFF:
697         return 70;
698     case ItemKindType::WAND:
699         return 50;
700     case ItemKindType::ROD:
701         return 90;
702     case ItemKindType::RING:
703     case ItemKindType::AMULET:
704         return 45;
705     case ItemKindType::FIGURINE:
706         return this->calc_figurine_value();
707     case ItemKindType::CAPTURE:
708         return this->calc_capture_value();
709     default:
710         return 0;
711     }
712 }
713
714 int ItemEntity::calc_figurine_value() const
715 {
716     auto figure_r_idx = i2enum<MonsterRaceId>(this->pval);
717     auto level = monraces_info[figure_r_idx].level;
718     if (level < 20) {
719         return level * 50L;
720     }
721
722     if (level < 30) {
723         return 1000 + (level - 20) * 150;
724     }
725
726     if (level < 40) {
727         return 2500 + (level - 30) * 350;
728     }
729
730     if (level < 50) {
731         return 6000 + (level - 40) * 800;
732     }
733
734     return 14000 + (level - 50) * 2000;
735 }
736
737 int ItemEntity::calc_capture_value() const
738 {
739     auto capture_r_idx = i2enum<MonsterRaceId>(this->pval);
740     if (!MonsterRace(capture_r_idx).is_valid()) {
741         return 1000;
742     }
743
744     return (monraces_info[capture_r_idx].level) * 50 + 1000;
745 }
746
747 bool ItemEntity::is_specific_artifact(FixedArtifactId id) const
748 {
749     return this->fixed_artifact_idx == id;
750 }
751
752 bool ItemEntity::has_unidentified_name() const
753 {
754     return this->bi_key.has_unidentified_name();
755 }
756
757 ItemKindType ItemEntity::get_arrow_kind() const
758 {
759     return this->bi_key.get_arrow_kind();
760 }
761
762 bool ItemEntity::is_wand_rod() const
763 {
764     return this->bi_key.is_wand_rod();
765 }
766
767 bool ItemEntity::is_wand_staff() const
768 {
769     return this->bi_key.is_wand_staff();
770 }
771
772 short ItemEntity::get_bow_energy() const
773 {
774     return this->bi_key.get_bow_energy();
775 }
776
777 int ItemEntity::get_arrow_magnification() const
778 {
779     return this->bi_key.get_arrow_magnification();
780 }
781
782 bool ItemEntity::is_aiming_rod() const
783 {
784     return this->bi_key.is_aiming_rod();
785 }
786
787 bool ItemEntity::is_lite_requiring_fuel() const
788 {
789     return this->bi_key.is_lite_requiring_fuel();
790 }
791
792 bool ItemEntity::is_junk() const
793 {
794     return this->bi_key.is_junk();
795 }
796
797 bool ItemEntity::is_armour() const
798 {
799     return this->bi_key.is_armour();
800 }
801
802 bool ItemEntity::is_cross_bow() const
803 {
804     return this->bi_key.is_cross_bow();
805 }
806
807 bool ItemEntity::is_inscribed() const
808 {
809     return this->inscription != std::nullopt;
810 }
811
812 /*!
813  * @brief オブジェクトから発動効果構造体を取得する。
814  * @return 発動効果構造体 (なかったら無効イテレータ)
815  */
816 std::vector<activation_type>::const_iterator ItemEntity::find_activation_info() const
817 {
818     const auto index = this->get_activation_index();
819     return std::find_if(activation_info.begin(), activation_info.end(), [index](const auto &x) { return x.index == index; });
820 }
821
822 bool ItemEntity::has_activation() const
823 {
824     return this->get_activation_index() != RandomArtActType::NONE;
825 }
826
827 BaseitemInfo &ItemEntity::get_baseitem() const
828 {
829     return baseitems_info[this->bi_id];
830 }
831
832 EgoItemDefinition &ItemEntity::get_ego() const
833 {
834     return egos_info.at(this->ego_idx);
835 }
836
837 ArtifactType &ItemEntity::get_fixed_artifact() const
838 {
839     return ArtifactsInfo::get_instance().get_artifact(this->fixed_artifact_idx);
840 }
841
842 TrFlags ItemEntity::get_flags() const
843 {
844     const auto &baseitem = this->get_baseitem();
845     auto flags = baseitem.flags;
846
847     if (this->is_fixed_artifact()) {
848         flags = this->get_fixed_artifact().flags;
849     }
850
851     if (this->is_ego()) {
852         const auto &ego = this->get_ego();
853         flags.set(ego.flags);
854         this->modify_ego_lite_flags(flags);
855     }
856
857     flags.set(this->art_flags);
858     if (auto effect = Smith::object_effect(this); effect) {
859         auto tr_flags = Smith::get_effect_tr_flags(*effect);
860         flags.set(tr_flags);
861     }
862
863     if (Smith::object_activation(this)) {
864         flags.set(TR_ACTIVATE);
865     }
866
867     return flags;
868 }
869
870 TrFlags ItemEntity::get_flags_known() const
871 {
872     TrFlags flags{};
873     if (!this->is_aware()) {
874         return flags;
875     }
876
877     const auto &baseitem = this->get_baseitem();
878     flags = baseitem.flags;
879     if (!this->is_known()) {
880         return flags;
881     }
882
883     if (this->is_ego()) {
884         const auto &ego = this->get_ego();
885         flags.set(ego.flags);
886         this->modify_ego_lite_flags(flags);
887     }
888
889     if (this->is_fully_known()) {
890         if (this->is_fixed_artifact()) {
891             flags = this->get_fixed_artifact().flags;
892         }
893
894         flags.set(this->art_flags);
895     }
896
897     if (auto effect = Smith::object_effect(this); effect) {
898         auto tr_flags = Smith::get_effect_tr_flags(*effect);
899         flags.set(tr_flags);
900     }
901
902     if (Smith::object_activation(this)) {
903         flags.set(TR_ACTIVATE);
904     }
905
906     return flags;
907 }
908
909 /*!
910  * @brief アイテムの発動効果名称を返す (ドラゴンブレス)
911  * @return 発動名称
912  */
913 std::string ItemEntity::build_activation_description_dragon_breath() const
914 {
915     std::stringstream ss;
916     ss << _("", "breathe ");
917     auto n = 0;
918     const auto flags = this->get_flags();
919     for (auto i = 0; dragonbreath_info[i].flag != 0; i++) {
920         if (flags.has(dragonbreath_info[i].flag)) {
921             if (n > 0) {
922                 ss << _("、", ", ");
923             }
924
925             ss << dragonbreath_info[i].name;
926             n++;
927         }
928     }
929
930     ss << _("のブレス(250)", " (250)");
931     return ss.str();
932 }
933
934 /*!
935  * @brief オブジェクトを鑑定済にする
936  */
937 void ItemEntity::mark_as_known()
938 {
939     this->feeling = FEEL_NONE;
940     this->ident &= ~(IDENT_SENSE);
941     this->ident &= ~(IDENT_EMPTY);
942     this->ident |= (IDENT_KNOWN);
943 }
944
945 /*!
946  * @brief オブジェクトを試行済にする
947  */
948 void ItemEntity::mark_as_tried()
949 {
950     this->get_baseitem().mark_as_tried();
951 }
952
953 /*!
954  * @brief エゴ光源のフラグを修正する
955  *
956  * 寿命のある光源で寿命が0ターンの時、光源エゴアイテムに起因するフラグは
957  * 灼熱エゴの火炎耐性を除き付与されないようにする。
958  *
959  * @param flags フラグ情報を受け取る配列
960  */
961 void ItemEntity::modify_ego_lite_flags(TrFlags &flags) const
962 {
963     if (this->bi_key.tval() != ItemKindType::LITE) {
964         return;
965     }
966
967     if (!this->is_lite_requiring_fuel() || this->fuel != 0) {
968         return;
969     }
970
971     switch (this->ego_idx) {
972     case EgoType::LITE_AURA_FIRE:
973         flags.reset(TR_SH_FIRE);
974         return;
975     case EgoType::LITE_INFRA:
976         flags.reset(TR_INFRA);
977         return;
978     case EgoType::LITE_EYE:
979         flags.reset({ TR_RES_BLIND, TR_SEE_INVIS });
980         return;
981     default:
982         return;
983     }
984 }
985
986 /*!
987  * @brief オブジェクトから能力発動IDを取得する。
988  * @details いくつかのケースで定義されている発動効果から、
989  * 鍛冶師による付与>固定アーティファクト>エゴ>ランダムアーティファクト>ベースアイテムの優先順位で走査していく。
990  * @param o_ptr 対象のオブジェクト構造体ポインタ
991  * @return 発動効果のIDを返す
992  */
993 RandomArtActType ItemEntity::get_activation_index() const
994 {
995     if (auto act_idx = Smith::object_activation(this); act_idx) {
996         return *act_idx;
997     }
998
999     if (this->is_fixed_artifact()) {
1000         const auto &artifact = this->get_fixed_artifact();
1001         if (artifact.flags.has(TR_ACTIVATE)) {
1002             return artifact.act_idx;
1003         }
1004     }
1005
1006     if (this->is_ego()) {
1007         const auto &ego = this->get_ego();
1008         if (ego.flags.has(TR_ACTIVATE)) {
1009             return ego.act_idx;
1010         }
1011     }
1012
1013     if (!this->is_random_artifact()) {
1014         const auto &baseitem = this->get_baseitem();
1015         if (baseitem.flags.has(TR_ACTIVATE)) {
1016             return baseitem.act_idx;
1017         }
1018     }
1019
1020     return this->activation_id;
1021 }