OSDN Git Service

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