OSDN Git Service

[Refactor] #3756 ItemEntity::is() とBaseitemKey::is() を定義した
[hengbandforosx/hengbandosx.git] / src / system / item-entity.cpp
index e338300..7ddc744 100644 (file)
@@ -1,45 +1,44 @@
-/*
+/*
  * @file item-entity.cpp
- * @brief ã\82¢ã\82¤ã\83\86ã\83 å®\9a義ã\81®æ§\8bé\80 ä½\93ã\81¨ã\82¨ã\83³ã\83\86ã\82£ã\83\86ã\82£å\87¦ç\90\86å®\9fè£\85
+ * @brief ã\82¢ã\82¤ã\83\86ã\83 å®\9fä½\93ã\81¨ã\81\9dã\82\8cã\81«ã\81¾ã\81¤ã\82\8fã\82\8bå\88¤å®\9aå\87¦ç\90\86群
  * @author Hourier
- * @date 2022/10/09
+ * @date 2022/11/25
+ * @details オブジェクトの状態を変更するメソッドは道半ば
  */
 
 #include "system/item-entity.h"
 #include "artifact/fixed-art-types.h"
 #include "artifact/random-art-effects.h"
 #include "monster-race/monster-race.h"
+#include "object-enchant/activation-info-table.h"
+#include "object-enchant/dragon-breaths-table.h"
+#include "object-enchant/item-feeling.h"
 #include "object-enchant/object-curse.h"
 #include "object-enchant/special-object-flags.h"
-#include "object-enchant/tr-types.h"
-#include "object-enchant/trc-types.h"
-#include "object-enchant/trg-types.h"
-#include "object/object-flags.h"
 #include "object/object-value.h"
 #include "object/tval-types.h"
 #include "smith/object-smith.h"
-#include "sv-definition/sv-armor-types.h"
 #include "sv-definition/sv-lite-types.h"
 #include "sv-definition/sv-other-types.h"
-#include "sv-definition/sv-protector-types.h"
+#include "sv-definition/sv-ring-types.h"
 #include "sv-definition/sv-weapon-types.h"
+#include "system/artifact-type-definition.h"
 #include "system/baseitem-info.h"
 #include "system/monster-race-info.h"
-#include "system/player-type-definition.h"
 #include "term/term-color-types.h"
 #include "util/bit-flags-calculator.h"
+#include "util/enum-converter.h"
 #include "util/string-processor.h"
-#include <set>
-#include <unordered_map>
+#include <sstream>
 
 ItemEntity::ItemEntity()
-    : fixed_artifact_idx(FixedArtifactId::NONE)
+    : bi_key(BaseitemKey(ItemKindType::NONE))
+    , fixed_artifact_idx(FixedArtifactId::NONE)
 {
 }
 
 /*!
- * @brief オブジェクトを初期化する
- * Wipe an object clean.
+ * @brief アイテムを初期化する
  */
 void ItemEntity::wipe()
 {
@@ -47,9 +46,8 @@ void ItemEntity::wipe()
 }
 
 /*!
- * @brief オブジェクトを複製する
- * Wipe an object clean.
- * @param j_ptr 複製元のオブジェクトの構造体参照ポインタ
+ * @brief アイテムを複製する
+ * @param j_ptr 複製元アイテムへの参照ポインタ
  */
 void ItemEntity::copy_from(const ItemEntity *j_ptr)
 {
@@ -57,219 +55,176 @@ void ItemEntity::copy_from(const ItemEntity *j_ptr)
 }
 
 /*!
- * @brief オブジェクト構造体にベースアイテムを作成する
- * @param player_ptr プレイヤーへの参照ポインタ
+ * @brief アイテム構造体にベースアイテムを作成する
  * @param bi_id 新たに作成したいベースアイテム情報のID
  */
 void ItemEntity::prep(short new_bi_id)
 {
-    auto *k_ptr = &baseitems_info[new_bi_id];
+    const auto &baseitem = baseitems_info[new_bi_id];
     auto old_stack_idx = this->stack_idx;
-    wipe();
+    this->wipe();
     this->stack_idx = old_stack_idx;
     this->bi_id = new_bi_id;
-    this->tval = k_ptr->bi_key.tval();
-    this->sval = k_ptr->bi_key.sval().value();
-    this->pval = k_ptr->pval;
+    this->bi_key = baseitem.bi_key;
+    this->pval = baseitem.pval;
     this->number = 1;
-    this->weight = k_ptr->weight;
-    this->to_h = k_ptr->to_h;
-    this->to_d = k_ptr->to_d;
-    this->to_a = k_ptr->to_a;
-    this->ac = k_ptr->ac;
-    this->dd = k_ptr->dd;
-    this->ds = k_ptr->ds;
-
-    if (k_ptr->act_idx > RandomArtActType::NONE) {
-        this->activation_id = k_ptr->act_idx;
-    }
-    if (baseitems_info[this->bi_id].cost <= 0) {
+    this->weight = baseitem.weight;
+    this->to_h = baseitem.to_h;
+    this->to_d = baseitem.to_d;
+    this->to_a = baseitem.to_a;
+    this->ac = baseitem.ac;
+    this->dd = baseitem.dd;
+    this->ds = baseitem.ds;
+
+    if (baseitem.act_idx > RandomArtActType::NONE) {
+        this->activation_id = baseitem.act_idx;
+    }
+
+    if (this->get_baseitem().cost <= 0) {
         this->ident |= (IDENT_BROKEN);
     }
 
-    if (k_ptr->gen_flags.has(ItemGenerationTraitType::CURSED)) {
+    if (baseitem.gen_flags.has(ItemGenerationTraitType::CURSED)) {
         this->curse_flags.set(CurseTraitType::CURSED);
     }
-    if (k_ptr->gen_flags.has(ItemGenerationTraitType::HEAVY_CURSE)) {
+
+    if (baseitem.gen_flags.has(ItemGenerationTraitType::HEAVY_CURSE)) {
         this->curse_flags.set(CurseTraitType::HEAVY_CURSE);
     }
-    if (k_ptr->gen_flags.has(ItemGenerationTraitType::PERMA_CURSE)) {
+
+    if (baseitem.gen_flags.has(ItemGenerationTraitType::PERMA_CURSE)) {
         this->curse_flags.set(CurseTraitType::PERMA_CURSE);
     }
-    if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE0)) {
+
+    if (baseitem.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE0)) {
         this->curse_flags.set(get_curse(0, this));
     }
-    if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE1)) {
+
+    if (baseitem.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE1)) {
         this->curse_flags.set(get_curse(1, this));
     }
-    if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE2)) {
+
+    if (baseitem.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE2)) {
         this->curse_flags.set(get_curse(2, this));
     }
 }
 
+bool ItemEntity::is(ItemKindType tval) const
+{
+    return this->bi_key.is(tval);
+}
+
 /*!
- * @brief オブジェクトが武器として装備できるかどうかを返す / Check if an object is weapon (including bows)
- * @return æ­¦å\99¨ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 武器か否かを判定する
+ * @return æ­¦å\99¨ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_weapon() const
 {
-    return (TV_WEAPON_BEGIN <= this->tval) && (this->tval <= TV_WEAPON_END);
+    return this->bi_key.is_weapon();
 }
 
 /*!
- * @brief オブジェクトが武器や矢弾として使用できるかを返す / Check if an object is weapon (including bows and ammo)
- * Rare weapons/aromors including Blade of Chaos, Dragon armors, etc.
- * @return 武器や矢弾として使えるならばtrueを返す
+ * @brief 武器や矢弾として使用できるかを判定する
+ * @return 武器や矢弾として使えるか否か
  */
 bool ItemEntity::is_weapon_ammo() const
 {
-    return (TV_MISSILE_BEGIN <= this->tval) && (this->tval <= TV_WEAPON_END);
+    return this->is_weapon() || this->is_ammo();
 }
 
 /*!
- * @brief オブジェクトが武器、防具、矢弾として使用できるかを返す / Check if an object is weapon, armour or ammo
- * @return æ­¦å\99¨ã\80\81é\98²å\85·ã\80\81ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 武器、防具、矢弾として使用できるかを判定する
+ * @return æ­¦å\99¨ã\80\81é\98²å\85·ã\80\81ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_weapon_armour_ammo() const
 {
-    return this->is_weapon_ammo() || this->is_armour();
+    return this->is_weapon_ammo() || this->is_protector();
 }
 
 /*!
- * @brief オブジェクトが近接武器として装備できるかを返す / Melee weapons
- * @return è¿\91æ\8e¥æ­¦å\99¨ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 近接武器として装備できるかを判定する
+ * @return è¿\91æ\8e¥æ­¦å\99¨ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_melee_weapon() const
 {
-    return (ItemKindType::DIGGING <= this->tval) && (this->tval <= ItemKindType::SWORD);
+    return this->bi_key.is_melee_weapon();
 }
 
 /*!
- * @brief エッセンスの付加可能な武器や矢弾かを返す
- * @return ã\82¨ã\83\83ã\82»ã\83³ã\82¹ã\81®ä»\98å\8a å\8f¯è\83½ã\81ªæ­¦å\99¨ã\81\8bç\9f¢å¼¾ã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99ã\80\82
+ * @brief エッセンスの付加可能な武器や矢弾かを判定する
+ * @return ã\82¨ã\83\83ã\82»ã\83³ã\82¹ã\81®ä»\98å\8a å\8f¯è\83½ã\81ªæ­¦å\99¨ã\81\8bç\9f¢å¼¾ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_melee_ammo() const
 {
-    switch (this->tval) {
-    case ItemKindType::HAFTED:
-    case ItemKindType::POLEARM:
-    case ItemKindType::DIGGING:
-    case ItemKindType::BOLT:
-    case ItemKindType::ARROW:
-    case ItemKindType::SHOT:
-        return true;
-    case ItemKindType::SWORD:
-        return this->sval != SV_POISON_NEEDLE;
-    default:
-        return false;
-    }
+    return this->bi_key.is_melee_ammo();
 }
 
 /*!
- * @brief オブジェクトが装備可能であるかを返す / Wearable including all weapon, all armour, bow, light source, amulet, and ring
- * @return è£\85å\82\99å\8f¯è\83½ã\81ªã\82\89ã\81°TRUEã\82\92è¿\94ã\81\99
+ * @brief 装備可能であるかを判定する
+ * @return è£\85å\82\99å\8f¯è\83½ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_wearable() const
 {
-    return (TV_WEARABLE_BEGIN <= this->tval) && (this->tval <= TV_WEARABLE_END);
+    return this->bi_key.is_wearable();
 }
 
 /*!
- * @brief オブジェクトが装備品であるかを返す(ItemEntity::is_wearableに矢弾を含む) / Equipment including all wearable objects and ammo
- * @return è£\85å\82\99å\93\81ã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 装備品であるかを判定する
+ * @return è£\85å\82\99å\93\81ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_equipment() const
 {
-    return (TV_EQUIP_BEGIN <= this->tval) && (this->tval <= TV_EQUIP_END);
+    return this->bi_key.is_equipement();
 }
 
 /*!
- * @brief 武器匠の「武器」鑑定対象になるかを判定する。/ Hook to specify "weapon"
- * @return 対象になるならtrueを返す。
+ * @brief 武器匠の「武器」鑑定対象になるかを判定する
+ * @return 鑑定対象か否か
  */
 bool ItemEntity::is_orthodox_melee_weapons() const
 {
-    switch (this->tval) {
-    case ItemKindType::HAFTED:
-    case ItemKindType::POLEARM:
-    case ItemKindType::DIGGING:
-        return true;
-    case ItemKindType::SWORD:
-        return this->sval != SV_POISON_NEEDLE;
-    default:
-        return false;
-    }
+    return this->bi_key.is_orthodox_melee_weapon();
 }
 
 /*!
- * @brief 修復対象となる壊れた武器かを判定する。 / Hook to specify "broken weapon"
- * @return ä¿®å¾©å¯¾è±¡ã\81«ã\81ªã\82\8bã\81ªã\82\89TRUEã\82\92è¿\94ã\81\99ã\80\82
+ * @brief 修復対象となる壊れた武器かを判定する
+ * @return ä¿®å¾©å¯¾è±¡ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_broken_weapon() const
 {
-    if (this->tval != ItemKindType::SWORD) {
-        return false;
-    }
-
-    switch (this->sval) {
-    case SV_BROKEN_DAGGER:
-    case SV_BROKEN_SWORD:
-        return true;
-    }
-
-    return false;
+    return this->bi_key.is_broken_weapon();
 }
 
 /*!
- * @brief オブジェクトが投射可能な武器かどうかを返す。
- * @return æ\8a\95å°\84å\8f¯è\83½ã\81ªæ­¦å\99¨ã\81ªã\82\89ã\81°true
+ * @brief 投射可能な武器かどうかを判定する
+ * @return æ\8a\95å°\84å\8f¯è\83½ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_throwable() const
 {
-    switch (this->tval) {
-    case ItemKindType::DIGGING:
-    case ItemKindType::HAFTED:
-    case ItemKindType::POLEARM:
-    case ItemKindType::SWORD:
-        return true;
-    default:
-        return false;
-    }
+    return this->bi_key.is_throwable();
 }
 
 /*!
- * @brief ã\82ªã\83\96ã\82¸ã\82§ã\82¯ã\83\88ã\81\8cã\81©ã\81¡ã\82\89ã\81®æ\89\8bã\81«ã\82\82è£\85å\82\99ã\81§ã\81\8dã\82\8bæ­¦å\99¨ã\81\8bã\81©ã\81\86ã\81\8bã\81®å\88¤å®\9a
- * @return 左右両方の手で装備できるならばtrueを返す。
+ * @brief ã\81©ã\81¡ã\82\89ã\81®æ\89\8bã\81«ã\82\82è£\85å\82\99ã\81§ã\81\8dã\82\8bæ­¦å\99¨ã\81\8bã\82\92å\88¤å®\9aã\81\99ã\82\8b
+ * @return 左右両方の手で装備可能か否か
  */
 bool ItemEntity::is_wieldable_in_etheir_hand() const
 {
-    switch (this->tval) {
-    case ItemKindType::DIGGING:
-    case ItemKindType::HAFTED:
-    case ItemKindType::POLEARM:
-    case ItemKindType::SWORD:
-    case ItemKindType::SHIELD:
-    case ItemKindType::CAPTURE:
-    case ItemKindType::CARD:
-        return true;
-    default:
-        return false;
-    }
+    return this->bi_key.is_wieldable_in_etheir_hand();
 }
 
 /*!
- * @brief オブジェクトが強化不能武器であるかを返す / Poison needle can not be enchanted
- * @return å¼·å\8c\96ä¸\8dè\83½ã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 強化不能武器であるかを判定する
+ * @return å¼·å\8c\96ä¸\8dè\83½ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::refuse_enchant_weapon() const
 {
-    return (this->tval == ItemKindType::SWORD) && (this->sval == SV_POISON_NEEDLE);
+    return this->bi_key.refuse_enchant_weapon();
 }
 
 /*!
- * @brief オブジェクトが強化可能武器であるかを返す /
- * Check if an object is weapon (including bows and ammo) and allows enchantment
- * @return 強化可能ならばtrueを返す
+ * @brief 強化可能武器であるかを判定する
+ * @return 強化可能か否か
  */
 bool ItemEntity::allow_enchant_weapon() const
 {
@@ -277,9 +232,8 @@ bool ItemEntity::allow_enchant_weapon() const
 }
 
 /*!
- * @brief オブジェクトが強化可能な近接武器であるかを返す /
- * Check if an object is melee weapon and allows enchantment
- * @return 強化可能な近接武器ならばtrueを返す
+ * @brief 強化可能な近接武器であるかを判定する
+ * @return 強化可能な近接武器か否か
  */
 bool ItemEntity::allow_enchant_melee_weapon() const
 {
@@ -287,84 +241,71 @@ bool ItemEntity::allow_enchant_melee_weapon() const
 }
 
 /*!
- * @brief オブジェクトが両手持ち可能な武器かを返す /
- * Check if an object is melee weapon and allows wielding with two-hands
- * @return 両手持ち可能ならばTRUEを返す
+ * @brief 両手持ち可能な武器かを判定する
+ * @return 両手持ち可能か否か
  */
 bool ItemEntity::allow_two_hands_wielding() const
 {
-    return this->is_melee_weapon() && ((this->weight > 99) || (this->tval == ItemKindType::POLEARM));
+    return this->is_melee_weapon() && ((this->weight > 99) || this->is(ItemKindType::POLEARM));
 }
 
 /*!
- * @brief オブジェクトが矢弾として使用できるかどうかを返す / Check if an object is ammo
- * @return ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 矢弾として使用できるかどうかを判定する
+ * @return ç\9f¢å¼¾ã\81¨ã\81\97ã\81¦ä½¿ã\81\88ã\82\8bã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_ammo() const
 {
-    return (TV_MISSILE_BEGIN <= this->tval) && (this->tval <= TV_MISSILE_END);
+    return this->bi_key.is_ammo();
 }
 
 /*!
- * @brief 対象のアイテムが矢やクロスボウの矢の材料になるかを返す。/
- * Hook to determine if an object is contertible in an arrow/bolt
- * @return 材料にできるならtrueを返す
+ * @brief 対象の矢やクロスボウの矢の材料になるかを判定する
+ * @return 材料にできるか否か
  */
 bool ItemEntity::is_convertible() const
 {
-    auto is_convertible = ((this->tval == ItemKindType::JUNK) || (this->tval == ItemKindType::SKELETON));
-    is_convertible |= ((this->tval == ItemKindType::CORPSE) && (this->sval == SV_SKELETON));
+    auto is_convertible = this->is(ItemKindType::JUNK) || this->is(ItemKindType::SKELETON);
+    is_convertible |= this->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_SKELETON);
     return is_convertible;
 }
 
 bool ItemEntity::is_lance() const
 {
-    auto is_lance = this->tval == ItemKindType::POLEARM;
-    is_lance &= (this->sval == SV_LANCE) || (this->sval == SV_HEAVY_LANCE);
+    auto is_lance = this->bi_key == BaseitemKey(ItemKindType::POLEARM, SV_LANCE);
+    is_lance |= this->bi_key == BaseitemKey(ItemKindType::POLEARM, SV_HEAVY_LANCE);
     return is_lance;
 }
 
 /*!
- * @brief オブジェクトが防具として装備できるかどうかを返す / Check if an object is armour
- * @return é\98²å\85·ã\81¨ã\81\97ã\81¦è£\85å\82\99ã\81§ã\81\8dã\82\8bã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief 防具かを判定する
+ * @return é\98²å\85·ã\81\8bå\90¦ã\81\8b
  */
-bool ItemEntity::is_armour() const
+bool ItemEntity::is_protector() const
 {
-    return (TV_ARMOR_BEGIN <= this->tval) && (this->tval <= TV_ARMOR_END);
+    return this->bi_key.is_protector();
 }
 
 /*!
- * @brief オブジェクトがレアアイテムかどうかを返す /
- * Rare weapons/aromors including Blade of Chaos, Dragon armors, etc.
- * @return レアアイテムならばTRUEを返す
+ * @brief オーラを纏える防具かどうかを判定する
+ * @return オーラを纏えるか否か
  */
-bool ItemEntity::is_rare() const
+bool ItemEntity::can_be_aura_protector() const
 {
-    static const std::unordered_map<ItemKindType, const std::set<OBJECT_SUBTYPE_VALUE>> rare_table = {
-        { ItemKindType::HAFTED, { SV_MACE_OF_DISRUPTION, SV_WIZSTAFF } },
-        { ItemKindType::POLEARM, { SV_SCYTHE_OF_SLICING, SV_DEATH_SCYTHE } },
-        { ItemKindType::SWORD, { SV_BLADE_OF_CHAOS, SV_DIAMOND_EDGE, SV_POISON_NEEDLE, SV_HAYABUSA } },
-        { ItemKindType::SHIELD, { SV_DRAGON_SHIELD, SV_MIRROR_SHIELD } },
-        { ItemKindType::HELM, { SV_DRAGON_HELM } },
-        { ItemKindType::BOOTS, { SV_PAIR_OF_DRAGON_GREAVE } },
-        { ItemKindType::CLOAK, { SV_ELVEN_CLOAK, SV_ETHEREAL_CLOAK, SV_SHADOW_CLOAK, SV_MAGIC_RESISTANCE_CLOAK } },
-        { ItemKindType::GLOVES, { SV_SET_OF_DRAGON_GLOVES } },
-        { ItemKindType::SOFT_ARMOR, { SV_KUROSHOUZOKU, SV_ABUNAI_MIZUGI } },
-        { ItemKindType::HARD_ARMOR, { SV_MITHRIL_CHAIN_MAIL, SV_MITHRIL_PLATE_MAIL, SV_ADAMANTITE_PLATE_MAIL } },
-        { ItemKindType::DRAG_ARMOR, { /* Any */ } },
-    };
-
-    if (auto it = rare_table.find(this->tval); it != rare_table.end()) {
-        const auto &svals = it->second;
-        return svals.empty() || (svals.find(this->sval) != svals.end());
-    }
+    return this->bi_key.can_be_aura_protector();
+}
 
-    return false;
+/*!
+ * @brief レアアイテムかどうかを判定する
+ * @return レアアイテムか否か
+ */
+bool ItemEntity::is_rare() const
+{
+    return this->bi_key.is_rare();
 }
 
 /*!
- * @brief ã\82ªã\83\96ã\82¸ã\82§ã\82¯ã\83\88ã\81\8cã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81\8bã\81©ã\81\86ã\81\8bã\82\92è¿\94ã\81\99
- * @return ã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81ªã\82\89ã\81°trueã\82\92è¿\94ã\81\99
+ * @brief ã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81\8bã\81©ã\81\86ã\81\8bã\82\92å\88¤å®\9aã\81\99ã\82\8b
+ * @return ã\82¨ã\82´ã\82¢ã\82¤ã\83\86ã\83 ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_ego() const
 {
@@ -372,29 +313,26 @@ bool ItemEntity::is_ego() const
 }
 
 /*!
- * @brief オブジェクトが鍛冶師のエッセンス付加済みかを返す /
- * Check if an object is made by a smith's special ability
- * @return エッセンス付加済みならばTRUEを返す
+ * @brief 鍛冶師のエッセンス付加済かを判定する
+ * @return エッセンス付加済か否か
  */
 bool ItemEntity::is_smith() const
 {
-    return Smith::object_effect(this).has_value() || Smith::object_activation(this).has_value();
+    return Smith::object_effect(this) || Smith::object_activation(this);
 }
 
 /*!
- * @brief オブジェクトがアーティファクトかを返す /
- * Check if an object is artifact
- * @return アーティファクトならばtrueを返す
+ * @brief 固定アーティファクトもしくはランダムアーティファクトであるかを判定する
+ * @return 固定アーティファクトもしくはランダムアーティファクトか否か
  */
-bool ItemEntity::is_artifact() const
+bool ItemEntity::is_fixed_or_random_artifact() const
 {
-    return this->is_fixed_artifact() || (this->art_name != 0);
+    return this->is_fixed_artifact() || this->randart_name;
 }
 
 /*!
- * @brief オブジェクトが固定アーティファクトかを返す /
- * Check if an object is fixed artifact
- * @return 固定アーティファクトならばtrueを返す
+ * @brief 固定アーティファクトかを判定する
+ * @return 固定アーティファクトか否か
  */
 bool ItemEntity::is_fixed_artifact() const
 {
@@ -402,23 +340,21 @@ bool ItemEntity::is_fixed_artifact() const
 }
 
 /*!
- * @brief オブジェクトがランダムアーティファクトかを返す /
- * Check if an object is random artifact
- * @return ランダムアーティファクトならばtrueを返す
+ * @brief ランダムアーティファクトかを判定する
+ * @return ランダムアーティファクトか否か
  */
 bool ItemEntity::is_random_artifact() const
 {
-    return this->is_artifact() && !this->is_fixed_artifact();
+    return this->is_fixed_or_random_artifact() && !this->is_fixed_artifact();
 }
 
 /*!
- * @brief オブジェクトが通常のアイテム(アーティファクト、エゴ、鍛冶師エッセンス付加いずれでもない)かを返す /
- * Check if an object is neither artifact, ego, nor 'smith' object
- * @return 通常のアイテムならばtrueを返す
+ * @brief 通常のアイテムかを返す
+ * @return アーティファクト、エゴ、鍛冶師エッセンス付加いずれでもないか、どれか1つであるか
  */
 bool ItemEntity::is_nameless() const
 {
-    return !this->is_artifact() && !this->is_ego() && !this->is_smith();
+    return !this->is_fixed_or_random_artifact() && !this->is_ego() && !this->is_smith();
 }
 
 bool ItemEntity::is_valid() const
@@ -442,13 +378,13 @@ bool ItemEntity::is_held_by_monster() const
 }
 
 /*
- * Determine if a given inventory item is "known"
- * Test One -- Check for special "known" tag
- * Test Two -- Check for "Easy Know" + "Aware"
+ * @brief 鑑定済かを判定する
+ * @return 鑑定済か否か
  */
 bool ItemEntity::is_known() const
 {
-    return any_bits(this->ident, IDENT_KNOWN) || (baseitems_info[this->bi_id].easy_know && baseitems_info[this->bi_id].aware);
+    const auto &baseitem = this->get_baseitem();
+    return any_bits(this->ident, IDENT_KNOWN) || (baseitem.easy_know && baseitem.aware);
 }
 
 bool ItemEntity::is_fully_known() const
@@ -457,89 +393,79 @@ bool ItemEntity::is_fully_known() const
 }
 
 /*!
- * @brief 与えられたオブジェクトのベースアイテムが鑑定済かを返す / Determine if a given inventory item is "aware"
- * @return é\91\91å®\9aæ¸\88ã\81ªã\82\89true
+ * @brief ベースアイテムが鑑定済かを判定する
+ * @return é\91\91å®\9aæ¸\88ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_aware() const
 {
-    return baseitems_info[this->bi_id].aware;
+    return this->get_baseitem().aware;
 }
 
 /*
- * Determine if a given inventory item is "tried"
+ * @brief ベースアイテムが試行済かを判定する
+ * @return 試行済か否か
  */
 bool ItemEntity::is_tried() const
 {
-    return baseitems_info[this->bi_id].tried;
+    return this->get_baseitem().tried;
 }
 
 /*!
- * @brief オブジェクトが薬であるかを返す
- * @return オブジェクトが薬ならばtrueを返す
+ * @brief 薬であるかを判定する
+ * @return 薬か否か
  */
 bool ItemEntity::is_potion() const
 {
-    return baseitems_info[this->bi_id].bi_key.tval() == ItemKindType::POTION;
+    return this->bi_key.is(ItemKindType::POTION);
 }
 
 /*!
- * @brief オブジェクトをプレイヤーが読むことができるかを判定する /
- * Hook to determine if an object is readable
- * @return 読むことが可能ならばtrueを返す
+ * @brief 読めるアイテムかを判定する
+ * @return 読めるか否か
  */
 bool ItemEntity::is_readable() const
 {
-    auto can_read = this->tval == ItemKindType::SCROLL;
-    can_read |= this->tval == ItemKindType::PARCHMENT;
+    auto can_read = this->is(ItemKindType::SCROLL);
+    can_read |= this->is(ItemKindType::PARCHMENT);
     can_read |= this->is_specific_artifact(FixedArtifactId::GHB);
     can_read |= this->is_specific_artifact(FixedArtifactId::POWER);
     return can_read;
 }
 
 /*!
- * @brief オブジェクトがランタンの燃料になるかどうかを判定する
- * An "item_tester_hook" for refilling lanterns
- * @return オブジェクトがランタンの燃料になるならばTRUEを返す
+ * @brief ランタンの燃料になるかを判定する
+ * @return ランタンの燃料になるか否か
  */
 bool ItemEntity::can_refill_lantern() const
 {
-    return (this->tval == ItemKindType::FLASK) || ((this->tval == ItemKindType::LITE) && (this->sval == SV_LITE_LANTERN));
+    return this->is(ItemKindType::FLASK) || (this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN));
 }
 
 /*!
- * @brief オブジェクトが松明に束ねられるかどうかを判定する
- * An "item_tester_hook" for refilling torches
- * @return オブジェクトが松明に束ねられるならばTRUEを返す
+ * @brief 松明に束ねられるかどうかを判定する
+ * @return 松明に束ねられるか否か
  */
 bool ItemEntity::can_refill_torch() const
 {
-    return (this->tval == ItemKindType::LITE) && (this->sval == SV_LITE_TORCH);
+    return this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_TORCH);
 }
 
 /*!
- * @brief 魔力充填が可能なアイテムかどうか判定する /
- * Hook for "get_item()".  Determine if something is rechargable.
- * @return 魔力充填が可能ならばTRUEを返す
+ * @brief 魔力充填が可能なアイテムかどうか判定する
+ * @return 魔力充填が可能か否か
  */
-bool ItemEntity::is_rechargeable() const
+bool ItemEntity::can_recharge() const
 {
-    switch (this->tval) {
-    case ItemKindType::STAFF:
-    case ItemKindType::WAND:
-    case ItemKindType::ROD:
-        return true;
-    default:
-        return false;
-    }
+    return this->bi_key.can_recharge();
 }
 
 /*!
- * @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを返す。 / An "item_tester_hook" for offer
- * @return ç\94\9fè´\84ã\81«ä½¿ç\94¨å\8f¯è\83½ã\81ªæ­»ä½\93ã\81ªã\82\89ã\81°TRUEã\82\92è¿\94ã\81\99ã\80\82
+ * @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを判定する
+ * @return ç\94\9fè´\84ã\81«ä½¿ç\94¨å\8f¯è\83½ã\81ªæ­»ä½\93ã\81\8bå\90¦ã\81\8b
  */
 bool ItemEntity::is_offerable() const
 {
-    if ((this->tval != ItemKindType::CORPSE) || (this->sval != SV_CORPSE)) {
+    if (this->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE)) {
         return false;
     }
 
@@ -547,9 +473,8 @@ bool ItemEntity::is_offerable() const
 }
 
 /*!
- * @brief オブジェクトをプレイヤーが魔道具として発動できるかを判定する /
- * Hook to determine if an object is activatable
- * @return 魔道具として発動可能ならばTRUEを返す
+ * @brief 魔道具として発動できるかを判定する
+ * @return 発動可能か否か
  */
 bool ItemEntity::is_activatable() const
 {
@@ -557,32 +482,33 @@ bool ItemEntity::is_activatable() const
         return false;
     }
 
-    auto flags = object_flags(this);
+    const auto flags = this->get_flags();
     return flags.has(TR_ACTIVATE);
 }
 
 /*!
- * @brief オブジェクトが燃料として使えるかを判定する
+ * @brief 燃料として使えるかを判定する
  * @return 燃料か否か
  */
 bool ItemEntity::is_fuel() const
 {
-    auto is_fuel = (this->tval == ItemKindType::LITE) && ((this->sval == SV_LITE_TORCH) || (this->sval == SV_LITE_LANTERN));
-    is_fuel |= BaseitemKey(this->tval, this->sval) == BaseitemKey(ItemKindType::FLASK, SV_FLASK_OIL);
+    auto is_fuel = this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_TORCH);
+    is_fuel |= this->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_LANTERN);
+    is_fuel |= this->bi_key == BaseitemKey(ItemKindType::FLASK, SV_FLASK_OIL);
     return is_fuel;
 }
 
 /*!
- * @brief オブジェクトが魔法書かどうかを判定する
+ * @brief 魔法書かどうかを判定する
  * @return 魔法書か否か
  */
 bool ItemEntity::is_spell_book() const
 {
-    return BaseitemKey(this->tval).is_spell_book();
+    return this->bi_key.is_spell_book();
 }
 
 /*!
- * @brief オブジェクトが同一の命中値上昇及びダメージ上昇があるかを判定する
+ * @brief 同一の命中値上昇及びダメージ上昇があるかを判定する
  * @return 同一修正か
  * @details 鍛冶師が篭手に殺戮エッセンスを付加した場合のみこの判定に意味がある
  */
@@ -604,7 +530,7 @@ bool ItemEntity::is_glove_same_temper(const ItemEntity *j_ptr) const
 }
 
 /*!
- * @brief ã\82ªã\83\96ã\82¸ã\82§ã\82¯ã\83\88ã\81\8cã\80\8c\81¤ã\81®ï½\9eï½\9eã\80\8dã\81¨é\87\8dã\81­ã\82\89ã\82\8cã\82\8bã\81\8bã\82\92ä¸\80è\88¬ç\9a\84ã\81«å\88¤å®\9aã\81\99ã\82\8b
+ * @brief 「2つの~~」と重ねられるかを一般的に判定する
  * @return 重ねられるか
  * @details 個別のアイテムによっては別途条件があるが、それはこの関数では判定しない
  */
@@ -634,7 +560,7 @@ bool ItemEntity::can_pile(const ItemEntity *j_ptr) const
         return false;
     }
 
-    if (this->is_artifact() || j_ptr->is_artifact()) {
+    if (this->is_fixed_or_random_artifact() || j_ptr->is_fixed_or_random_artifact()) {
         return false;
     }
 
@@ -679,14 +605,14 @@ bool ItemEntity::can_pile(const ItemEntity *j_ptr) const
  */
 TERM_COLOR ItemEntity::get_color() const
 {
-    const auto &baseitem = baseitems_info[this->bi_id];
+    const auto &baseitem = this->get_baseitem();
     const auto flavor = baseitem.flavor;
     if (flavor != 0) {
         return baseitems_info[flavor].x_attr;
     }
 
-    auto has_attr = this->bi_id == 0;
-    has_attr |= (this->tval != ItemKindType::CORPSE) || (this->sval != SV_CORPSE);
+    auto has_attr = !this->is_valid();
+    has_attr |= this->bi_key != BaseitemKey(ItemKindType::CORPSE, SV_CORPSE);
     has_attr |= baseitem.x_attr != TERM_DARK;
     if (has_attr) {
         return baseitem.x_attr;
@@ -703,14 +629,14 @@ TERM_COLOR ItemEntity::get_color() const
  */
 char ItemEntity::get_symbol() const
 {
-    const auto &baseitem = baseitems_info[this->bi_id];
+    const auto &baseitem = this->get_baseitem();
     const auto flavor = baseitem.flavor;
     return flavor ? baseitems_info[flavor].x_char : baseitem.x_char;
 }
 
 /*!
- * @brief ã\82ªã\83\96ã\82¸ã\82§ã\82¯ã\83\88価格算出のメインルーチン
- * @return オブジェクトの判明している現価格
+ * @brief ã\82¢ã\82¤ã\83\86ã\83 価格算出のメインルーチン
+ * @return 判明している現価格
  */
 int ItemEntity::get_price() const
 {
@@ -744,10 +670,10 @@ int ItemEntity::get_price() const
 int ItemEntity::get_baseitem_price() const
 {
     if (this->is_aware()) {
-        return baseitems_info[this->bi_id].cost;
+        return this->get_baseitem().cost;
     }
 
-    switch (this->tval) {
+    switch (this->bi_key.tval()) {
     case ItemKindType::FOOD:
         return 5;
     case ItemKindType::POTION:
@@ -808,3 +734,411 @@ bool ItemEntity::is_specific_artifact(FixedArtifactId id) const
 {
     return this->fixed_artifact_idx == id;
 }
+
+bool ItemEntity::has_unidentified_name() const
+{
+    return this->bi_key.has_unidentified_name();
+}
+
+ItemKindType ItemEntity::get_arrow_kind() const
+{
+    return this->bi_key.get_arrow_kind();
+}
+
+bool ItemEntity::is_wand_rod() const
+{
+    return this->bi_key.is_wand_rod();
+}
+
+bool ItemEntity::is_wand_staff() const
+{
+    return this->bi_key.is_wand_staff();
+}
+
+short ItemEntity::get_bow_energy() const
+{
+    return this->bi_key.get_bow_energy();
+}
+
+int ItemEntity::get_arrow_magnification() const
+{
+    return this->bi_key.get_arrow_magnification();
+}
+
+bool ItemEntity::is_aiming_rod() const
+{
+    return this->bi_key.is_aiming_rod();
+}
+
+bool ItemEntity::is_lite_requiring_fuel() const
+{
+    return this->bi_key.is_lite_requiring_fuel();
+}
+
+bool ItemEntity::is_junk() const
+{
+    return this->bi_key.is_junk();
+}
+
+bool ItemEntity::is_armour() const
+{
+    return this->bi_key.is_armour();
+}
+
+bool ItemEntity::is_cross_bow() const
+{
+    return this->bi_key.is_cross_bow();
+}
+
+bool ItemEntity::is_inscribed() const
+{
+    return this->inscription != std::nullopt;
+}
+
+/*!
+ * @brief オブジェクトから発動効果構造体を取得する。
+ * @return 発動効果構造体 (なかったら無効イテレータ)
+ */
+std::vector<activation_type>::const_iterator ItemEntity::find_activation_info() const
+{
+    const auto index = this->get_activation_index();
+    return std::find_if(activation_info.begin(), activation_info.end(), [index](const auto &x) { return x.index == index; });
+}
+
+bool ItemEntity::has_activation() const
+{
+    return this->get_activation_index() != RandomArtActType::NONE;
+}
+
+BaseitemInfo &ItemEntity::get_baseitem() const
+{
+    return baseitems_info[this->bi_id];
+}
+
+EgoItemDefinition &ItemEntity::get_ego() const
+{
+    return egos_info.at(this->ego_idx);
+}
+
+ArtifactType &ItemEntity::get_fixed_artifact() const
+{
+    return ArtifactsInfo::get_instance().get_artifact(this->fixed_artifact_idx);
+}
+
+TrFlags ItemEntity::get_flags() const
+{
+    const auto &baseitem = this->get_baseitem();
+    auto flags = baseitem.flags;
+
+    if (this->is_fixed_artifact()) {
+        flags = this->get_fixed_artifact().flags;
+    }
+
+    if (this->is_ego()) {
+        const auto &ego = this->get_ego();
+        flags.set(ego.flags);
+        this->modify_ego_lite_flags(flags);
+    }
+
+    flags.set(this->art_flags);
+    if (auto effect = Smith::object_effect(this); effect) {
+        auto tr_flags = Smith::get_effect_tr_flags(*effect);
+        flags.set(tr_flags);
+    }
+
+    if (Smith::object_activation(this)) {
+        flags.set(TR_ACTIVATE);
+    }
+
+    return flags;
+}
+
+TrFlags ItemEntity::get_flags_known() const
+{
+    TrFlags flags{};
+    if (!this->is_aware()) {
+        return flags;
+    }
+
+    const auto &baseitem = this->get_baseitem();
+    flags = baseitem.flags;
+    if (!this->is_known()) {
+        return flags;
+    }
+
+    if (this->is_ego()) {
+        const auto &ego = this->get_ego();
+        flags.set(ego.flags);
+        this->modify_ego_lite_flags(flags);
+    }
+
+    if (this->is_fully_known()) {
+        if (this->is_fixed_artifact()) {
+            flags = this->get_fixed_artifact().flags;
+        }
+
+        flags.set(this->art_flags);
+    }
+
+    if (auto effect = Smith::object_effect(this); effect) {
+        auto tr_flags = Smith::get_effect_tr_flags(*effect);
+        flags.set(tr_flags);
+    }
+
+    if (Smith::object_activation(this)) {
+        flags.set(TR_ACTIVATE);
+    }
+
+    return flags;
+}
+
+/*!
+ * @brief 発動効果の記述を生成する (メインルーチン)
+ * @return 発動効果
+ */
+std::string ItemEntity::explain_activation() const
+{
+    const auto flags = this->get_flags();
+    if (flags.has_not(TR_ACTIVATE)) {
+        return _("なし", "nothing");
+    }
+
+    if (this->has_activation()) {
+        return this->build_activation_description();
+    }
+
+    const auto tval = this->bi_key.tval();
+    if (tval == ItemKindType::WHISTLE) {
+        return _("ペット呼び寄せ : 100+d100ターン毎", "call pet every 100+d100 turns");
+    }
+
+    if (tval == ItemKindType::CAPTURE) {
+        return _("モンスターを捕える、又は解放する。", "captures or releases a monster.");
+    }
+
+    return _("何も起きない", "Nothing");
+}
+
+std::string ItemEntity::build_timeout_description(const activation_type &act) const
+{
+    const auto constant = act.timeout.constant;
+    const auto dice = act.timeout.dice;
+    if (constant == 0 && dice == 0) {
+        return _("いつでも", "every turn");
+    }
+
+    if (constant >= 0) {
+        std::stringstream ss;
+        ss << _("", "every ");
+        if (constant > 0) {
+            ss << constant;
+            if (dice > 0) {
+                ss << '+';
+            }
+        }
+
+        if (dice > 0) {
+            ss << 'd' << dice;
+        }
+
+        ss << _(" ターン毎", " turns");
+        return ss.str();
+    }
+
+    std::stringstream ss;
+    switch (act.index) {
+    case RandomArtActType::BR_FIRE:
+        ss << _("", "every ") << (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES) ? 200 : 250) << _(" ターン毎", " turns");
+        return ss.str();
+    case RandomArtActType::BR_COLD:
+        ss << _("", "every ") << (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE) ? 200 : 250) << _(" ターン毎", " turns");
+        return ss.str();
+    case RandomArtActType::TERROR:
+        return _("3*(レベル+10) ターン毎", "every 3 * (level+10) turns");
+    case RandomArtActType::MURAMASA:
+        return _("確率50%で壊れる", "(destroyed 50%)");
+    default:
+        return "undefined";
+    }
+}
+
+/*!
+ * @brief 発動効果の記述を生成する(サブルーチン/汎用)
+ * @return 発動効果
+ */
+std::string ItemEntity::build_activation_description() const
+{
+    const auto it = this->find_activation_info();
+    if (it == activation_info.end()) {
+        return _("未定義", "something undefined");
+    }
+
+    const auto activation_description = this->build_activation_description(*it);
+    const auto timeout_description = this->build_timeout_description(*it);
+    std::stringstream ss;
+    ss << activation_description << _(" : ", " ") << timeout_description;
+    return ss.str();
+}
+
+/*!
+ * @brief 鑑定済にする
+ */
+void ItemEntity::mark_as_known()
+{
+    this->feeling = FEEL_NONE;
+    this->ident &= ~(IDENT_SENSE);
+    this->ident &= ~(IDENT_EMPTY);
+    this->ident |= (IDENT_KNOWN);
+}
+
+/*!
+ * @brief 試行済にする
+ */
+void ItemEntity::mark_as_tried()
+{
+    this->get_baseitem().mark_as_tried();
+}
+
+/*!
+ * @brief エゴ光源のフラグを修正する
+ *
+ * 寿命のある光源で寿命が0ターンの時、光源エゴアイテムに起因するフラグは
+ * 灼熱エゴの火炎耐性を除き付与されないようにする。
+ *
+ * @param flags フラグ情報を受け取る配列
+ */
+void ItemEntity::modify_ego_lite_flags(TrFlags &flags) const
+{
+    if (!this->bi_key.is(ItemKindType::LITE)) {
+        return;
+    }
+
+    if (!this->is_lite_requiring_fuel() || this->fuel != 0) {
+        return;
+    }
+
+    switch (this->ego_idx) {
+    case EgoType::LITE_AURA_FIRE:
+        flags.reset(TR_SH_FIRE);
+        return;
+    case EgoType::LITE_INFRA:
+        flags.reset(TR_INFRA);
+        return;
+    case EgoType::LITE_EYE:
+        flags.reset({ TR_RES_BLIND, TR_SEE_INVIS });
+        return;
+    default:
+        return;
+    }
+}
+
+/*!
+ * @brief 発動効果IDを取得する
+ * @details いくつかのケースで定義されている発動効果から、
+ * 鍛冶師による付与>固定アーティファクト>エゴ>ランダムアーティファクト>ベースアイテムの優先順位で走査する
+ * @return 発動効果ID
+ */
+RandomArtActType ItemEntity::get_activation_index() const
+{
+    if (auto act_idx = Smith::object_activation(this); act_idx) {
+        return *act_idx;
+    }
+
+    if (this->is_fixed_artifact()) {
+        const auto &artifact = this->get_fixed_artifact();
+        if (artifact.flags.has(TR_ACTIVATE)) {
+            return artifact.act_idx;
+        }
+    }
+
+    if (this->is_ego()) {
+        const auto &ego = this->get_ego();
+        if (ego.flags.has(TR_ACTIVATE)) {
+            return ego.act_idx;
+        }
+    }
+
+    if (!this->is_random_artifact()) {
+        const auto &baseitem = this->get_baseitem();
+        if (baseitem.flags.has(TR_ACTIVATE)) {
+            return baseitem.act_idx;
+        }
+    }
+
+    return this->activation_id;
+}
+
+std::string ItemEntity::build_activation_description(const activation_type &act) const
+{
+    switch (act.index) {
+    case RandomArtActType::NONE:
+        return act.desc;
+    case RandomArtActType::BR_FIRE:
+        if (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_FLAMES)) {
+            return _("火炎のブレス (200) と火への耐性", "breathe fire (200) and resist fire");
+        }
+
+        return act.desc;
+    case RandomArtActType::BR_COLD:
+        if (this->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_ICE)) {
+            return _("冷気のブレス (200) と冷気への耐性", "breathe cold (200) and resist cold");
+        }
+
+        return act.desc;
+    case RandomArtActType::BR_DRAGON:
+        return this->build_activation_description_dragon_breath();
+    case RandomArtActType::AGGRAVATE:
+        if (this->is_specific_artifact(FixedArtifactId::HYOUSIGI)) {
+            return _("拍子木を打ちならす", "beat wooden clappers");
+        }
+
+        return act.desc;
+    case RandomArtActType::ACID_BALL_AND_RESISTANCE:
+        return _("アシッド・ボール (100) と酸への耐性", "ball of acid (100) and resist acid");
+    case RandomArtActType::FIRE_BALL_AND_RESISTANCE:
+        return _("ファイア・ボール (100) と火への耐性", "ball of fire (100) and resist fire");
+    case RandomArtActType::COLD_BALL_AND_RESISTANCE:
+        return _("アイス・ボール (100) と冷気への耐性", "ball of cold (100) and resist cold");
+    case RandomArtActType::ELEC_BALL_AND_RESISTANCE:
+        return _("サンダー・ボール (100) と電撃への耐性", "ball of elec (100) and resist elec");
+    case RandomArtActType::POIS_BALL_AND_RESISTANCE:
+        return _("ポイズン・ボール (100) と毒への耐性", "ball of poison (100) and resist elec");
+    case RandomArtActType::RESIST_ACID:
+        return _("一時的な酸への耐性", "temporary resist acid");
+    case RandomArtActType::RESIST_FIRE:
+        return _("一時的な火への耐性", "temporary resist fire");
+    case RandomArtActType::RESIST_COLD:
+        return _("一時的な冷気への耐性", "temporary resist cold");
+    case RandomArtActType::RESIST_ELEC:
+        return _("一時的な電撃への耐性", "temporary resist elec");
+    case RandomArtActType::RESIST_POIS:
+        return _("一時的な毒への耐性", "temporary resist elec");
+    default:
+        return act.desc;
+    }
+}
+
+/*!
+ * @brief 発動効果の記述を返す (ドラゴンブレス)
+ * @return 発動効果
+ */
+std::string ItemEntity::build_activation_description_dragon_breath() const
+{
+    std::stringstream ss;
+    ss << _("", "breathe ");
+    auto n = 0;
+    const auto flags = this->get_flags();
+    for (auto i = 0; dragonbreath_info[i].flag != 0; i++) {
+        if (flags.has(dragonbreath_info[i].flag)) {
+            if (n > 0) {
+                ss << _("、", ", ");
+            }
+
+            ss << dragonbreath_info[i].name;
+            n++;
+        }
+    }
+
+    ss << _("のブレス(250)", " (250)");
+    return ss.str();
+}