OSDN Git Service

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