OSDN Git Service

[Refactor] #2628 Renamed object-type-definition.cpp/h to item-entity.cpp/h
[hengbandforosx/hengbandosx.git] / src / system / item-entity.cpp
1 /*
2  * @file item-entity.cpp
3  * @brief アイテム定義の構造体とエンティティ処理実装
4  * @author Hourier
5  * @date 2022/10/09
6  */
7
8 #include "system/item-entity.h"
9 #include "artifact/fixed-art-types.h"
10 #include "artifact/random-art-effects.h"
11 #include "monster-race/monster-race.h"
12 #include "object-enchant/object-curse.h"
13 #include "object-enchant/special-object-flags.h"
14 #include "object-enchant/tr-types.h"
15 #include "object-enchant/trc-types.h"
16 #include "object-enchant/trg-types.h"
17 #include "object/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-armor-types.h"
22 #include "sv-definition/sv-lite-types.h"
23 #include "sv-definition/sv-other-types.h"
24 #include "sv-definition/sv-protector-types.h"
25 #include "sv-definition/sv-weapon-types.h"
26 #include "system/baseitem-info-definition.h"
27 #include "system/monster-race-definition.h"
28 #include "system/player-type-definition.h"
29 #include "term/term-color-types.h"
30 #include "util/bit-flags-calculator.h"
31 #include "util/string-processor.h"
32 #include <set>
33 #include <unordered_map>
34
35 ItemEntity::ItemEntity()
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  * Prepare an object based on an object kind.
62  * @param player_ptr プレイヤーへの参照ポインタ
63  * @param k_idx 新たに作成したいベースアイテム情報のID
64  */
65 void ItemEntity::prep(KIND_OBJECT_IDX ko_idx)
66 {
67     auto *k_ptr = &baseitems_info[ko_idx];
68     auto old_stack_idx = this->stack_idx;
69     wipe();
70     this->stack_idx = old_stack_idx;
71     this->k_idx = ko_idx;
72     this->tval = k_ptr->bi_key.tval();
73     this->sval = k_ptr->bi_key.sval().value();
74     this->pval = k_ptr->pval;
75     this->number = 1;
76     this->weight = k_ptr->weight;
77     this->to_h = k_ptr->to_h;
78     this->to_d = k_ptr->to_d;
79     this->to_a = k_ptr->to_a;
80     this->ac = k_ptr->ac;
81     this->dd = k_ptr->dd;
82     this->ds = k_ptr->ds;
83
84     if (k_ptr->act_idx > RandomArtActType::NONE) {
85         this->activation_id = k_ptr->act_idx;
86     }
87     if (baseitems_info[this->k_idx].cost <= 0) {
88         this->ident |= (IDENT_BROKEN);
89     }
90
91     if (k_ptr->gen_flags.has(ItemGenerationTraitType::CURSED)) {
92         this->curse_flags.set(CurseTraitType::CURSED);
93     }
94     if (k_ptr->gen_flags.has(ItemGenerationTraitType::HEAVY_CURSE)) {
95         this->curse_flags.set(CurseTraitType::HEAVY_CURSE);
96     }
97     if (k_ptr->gen_flags.has(ItemGenerationTraitType::PERMA_CURSE)) {
98         this->curse_flags.set(CurseTraitType::PERMA_CURSE);
99     }
100     if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE0)) {
101         this->curse_flags.set(get_curse(0, this));
102     }
103     if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE1)) {
104         this->curse_flags.set(get_curse(1, this));
105     }
106     if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE2)) {
107         this->curse_flags.set(get_curse(2, this));
108     }
109 }
110
111 /*!
112  * @brief オブジェクトが武器として装備できるかどうかを返す / Check if an object is weapon (including bows)
113  * @return 武器として使えるならばtrueを返す
114  */
115 bool ItemEntity::is_weapon() const
116 {
117     return (TV_WEAPON_BEGIN <= this->tval) && (this->tval <= TV_WEAPON_END);
118 }
119
120 /*!
121  * @brief オブジェクトが武器や矢弾として使用できるかを返す / Check if an object is weapon (including bows and ammo)
122  * Rare weapons/aromors including Blade of Chaos, Dragon armors, etc.
123  * @return 武器や矢弾として使えるならばtrueを返す
124  */
125 bool ItemEntity::is_weapon_ammo() const
126 {
127     return (TV_MISSILE_BEGIN <= this->tval) && (this->tval <= TV_WEAPON_END);
128 }
129
130 /*!
131  * @brief オブジェクトが武器、防具、矢弾として使用できるかを返す / Check if an object is weapon, armour or ammo
132  * @return 武器、防具、矢弾として使えるならばtrueを返す
133  */
134 bool ItemEntity::is_weapon_armour_ammo() const
135 {
136     return this->is_weapon_ammo() || this->is_armour();
137 }
138
139 /*!
140  * @brief オブジェクトが近接武器として装備できるかを返す / Melee weapons
141  * @return 近接武器として使えるならばtrueを返す
142  */
143 bool ItemEntity::is_melee_weapon() const
144 {
145     return (ItemKindType::DIGGING <= this->tval) && (this->tval <= ItemKindType::SWORD);
146 }
147
148 /*!
149  * @brief エッセンスの付加可能な武器や矢弾かを返す
150  * @return エッセンスの付加可能な武器か矢弾ならばtrueを返す。
151  */
152 bool ItemEntity::is_melee_ammo() const
153 {
154     switch (this->tval) {
155     case ItemKindType::HAFTED:
156     case ItemKindType::POLEARM:
157     case ItemKindType::DIGGING:
158     case ItemKindType::BOLT:
159     case ItemKindType::ARROW:
160     case ItemKindType::SHOT:
161         return true;
162     case ItemKindType::SWORD:
163         return this->sval != SV_POISON_NEEDLE;
164     default:
165         return false;
166     }
167 }
168
169 /*!
170  * @brief オブジェクトが装備可能であるかを返す / Wearable including all weapon, all armour, bow, light source, amulet, and ring
171  * @return 装備可能ならばTRUEを返す
172  */
173 bool ItemEntity::is_wearable() const
174 {
175     return (TV_WEARABLE_BEGIN <= this->tval) && (this->tval <= TV_WEARABLE_END);
176 }
177
178 /*!
179  * @brief オブジェクトが装備品であるかを返す(ItemEntity::is_wearableに矢弾を含む) / Equipment including all wearable objects and ammo
180  * @return 装備品ならばtrueを返す
181  */
182 bool ItemEntity::is_equipment() const
183 {
184     return (TV_EQUIP_BEGIN <= this->tval) && (this->tval <= TV_EQUIP_END);
185 }
186
187 /*!
188  * @brief 武器匠の「武器」鑑定対象になるかを判定する。/ Hook to specify "weapon"
189  * @return 対象になるならtrueを返す。
190  */
191 bool ItemEntity::is_orthodox_melee_weapons() const
192 {
193     switch (this->tval) {
194     case ItemKindType::HAFTED:
195     case ItemKindType::POLEARM:
196     case ItemKindType::DIGGING:
197         return true;
198     case ItemKindType::SWORD:
199         return this->sval != SV_POISON_NEEDLE;
200     default:
201         return false;
202     }
203 }
204
205 /*!
206  * @brief 修復対象となる壊れた武器かを判定する。 / Hook to specify "broken weapon"
207  * @return 修復対象になるならTRUEを返す。
208  */
209 bool ItemEntity::is_broken_weapon() const
210 {
211     if (this->tval != ItemKindType::SWORD) {
212         return false;
213     }
214
215     switch (this->sval) {
216     case SV_BROKEN_DAGGER:
217     case SV_BROKEN_SWORD:
218         return true;
219     }
220
221     return false;
222 }
223
224 /*!
225  * @brief オブジェクトが投射可能な武器かどうかを返す。
226  * @return 投射可能な武器ならばtrue
227  */
228 bool ItemEntity::is_throwable() const
229 {
230     switch (this->tval) {
231     case ItemKindType::DIGGING:
232     case ItemKindType::HAFTED:
233     case ItemKindType::POLEARM:
234     case ItemKindType::SWORD:
235         return true;
236     default:
237         return false;
238     }
239 }
240
241 /*!
242  * @brief オブジェクトがどちらの手にも装備できる武器かどうかの判定
243  * @return 左右両方の手で装備できるならばtrueを返す。
244  */
245 bool ItemEntity::is_wieldable_in_etheir_hand() const
246 {
247     switch (this->tval) {
248     case ItemKindType::DIGGING:
249     case ItemKindType::HAFTED:
250     case ItemKindType::POLEARM:
251     case ItemKindType::SWORD:
252     case ItemKindType::SHIELD:
253     case ItemKindType::CAPTURE:
254     case ItemKindType::CARD:
255         return true;
256     default:
257         return false;
258     }
259 }
260
261 /*!
262  * @brief オブジェクトが強化不能武器であるかを返す / Poison needle can not be enchanted
263  * @return 強化不能ならばtrueを返す
264  */
265 bool ItemEntity::refuse_enchant_weapon() const
266 {
267     return (this->tval == ItemKindType::SWORD) && (this->sval == SV_POISON_NEEDLE);
268 }
269
270 /*!
271  * @brief オブジェクトが強化可能武器であるかを返す /
272  * Check if an object is weapon (including bows and ammo) and allows enchantment
273  * @return 強化可能ならばtrueを返す
274  */
275 bool ItemEntity::allow_enchant_weapon() const
276 {
277     return this->is_weapon_ammo() && !this->refuse_enchant_weapon();
278 }
279
280 /*!
281  * @brief オブジェクトが強化可能な近接武器であるかを返す /
282  * Check if an object is melee weapon and allows enchantment
283  * @return 強化可能な近接武器ならばtrueを返す
284  */
285 bool ItemEntity::allow_enchant_melee_weapon() const
286 {
287     return this->is_melee_weapon() && !this->refuse_enchant_weapon();
288 }
289
290 /*!
291  * @brief オブジェクトが両手持ち可能な武器かを返す /
292  * Check if an object is melee weapon and allows wielding with two-hands
293  * @return 両手持ち可能ならばTRUEを返す
294  */
295 bool ItemEntity::allow_two_hands_wielding() const
296 {
297     return this->is_melee_weapon() && ((this->weight > 99) || (this->tval == ItemKindType::POLEARM));
298 }
299
300 /*!
301  * @brief オブジェクトが矢弾として使用できるかどうかを返す / Check if an object is ammo
302  * @return 矢弾として使えるならばtrueを返す
303  */
304 bool ItemEntity::is_ammo() const
305 {
306     return (TV_MISSILE_BEGIN <= this->tval) && (this->tval <= TV_MISSILE_END);
307 }
308
309 /*!
310  * @brief 対象のアイテムが矢やクロスボウの矢の材料になるかを返す。/
311  * Hook to determine if an object is contertible in an arrow/bolt
312  * @return 材料にできるならtrueを返す
313  */
314 bool ItemEntity::is_convertible() const
315 {
316     auto is_convertible = ((this->tval == ItemKindType::JUNK) || (this->tval == ItemKindType::SKELETON));
317     is_convertible |= ((this->tval == ItemKindType::CORPSE) && (this->sval == SV_SKELETON));
318     return is_convertible;
319 }
320
321 bool ItemEntity::is_lance() const
322 {
323     auto is_lance = this->tval == ItemKindType::POLEARM;
324     is_lance &= (this->sval == SV_LANCE) || (this->sval == SV_HEAVY_LANCE);
325     return is_lance;
326 }
327
328 /*!
329  * @brief オブジェクトが防具として装備できるかどうかを返す / Check if an object is armour
330  * @return 防具として装備できるならばtrueを返す
331  */
332 bool ItemEntity::is_armour() const
333 {
334     return (TV_ARMOR_BEGIN <= this->tval) && (this->tval <= TV_ARMOR_END);
335 }
336
337 /*!
338  * @brief オブジェクトがレアアイテムかどうかを返す /
339  * Rare weapons/aromors including Blade of Chaos, Dragon armors, etc.
340  * @return レアアイテムならばTRUEを返す
341  */
342 bool ItemEntity::is_rare() const
343 {
344     static const std::unordered_map<ItemKindType, const std::set<OBJECT_SUBTYPE_VALUE>> rare_table = {
345         { ItemKindType::HAFTED, { SV_MACE_OF_DISRUPTION, SV_WIZSTAFF } },
346         { ItemKindType::POLEARM, { SV_SCYTHE_OF_SLICING, SV_DEATH_SCYTHE } },
347         { ItemKindType::SWORD, { SV_BLADE_OF_CHAOS, SV_DIAMOND_EDGE, SV_POISON_NEEDLE, SV_HAYABUSA } },
348         { ItemKindType::SHIELD, { SV_DRAGON_SHIELD, SV_MIRROR_SHIELD } },
349         { ItemKindType::HELM, { SV_DRAGON_HELM } },
350         { ItemKindType::BOOTS, { SV_PAIR_OF_DRAGON_GREAVE } },
351         { ItemKindType::CLOAK, { SV_ELVEN_CLOAK, SV_ETHEREAL_CLOAK, SV_SHADOW_CLOAK, SV_MAGIC_RESISTANCE_CLOAK } },
352         { ItemKindType::GLOVES, { SV_SET_OF_DRAGON_GLOVES } },
353         { ItemKindType::SOFT_ARMOR, { SV_KUROSHOUZOKU, SV_ABUNAI_MIZUGI } },
354         { ItemKindType::HARD_ARMOR, { SV_MITHRIL_CHAIN_MAIL, SV_MITHRIL_PLATE_MAIL, SV_ADAMANTITE_PLATE_MAIL } },
355         { ItemKindType::DRAG_ARMOR, { /* Any */ } },
356     };
357
358     if (auto it = rare_table.find(this->tval); it != rare_table.end()) {
359         const auto &svals = it->second;
360         return svals.empty() || (svals.find(this->sval) != svals.end());
361     }
362
363     return false;
364 }
365
366 /*!
367  * @brief オブジェクトがエゴアイテムかどうかを返す
368  * @return エゴアイテムならばtrueを返す
369  */
370 bool ItemEntity::is_ego() const
371 {
372     return this->ego_idx != EgoType::NONE;
373 }
374
375 /*!
376  * @brief オブジェクトが鍛冶師のエッセンス付加済みかを返す /
377  * Check if an object is made by a smith's special ability
378  * @return エッセンス付加済みならばTRUEを返す
379  */
380 bool ItemEntity::is_smith() const
381 {
382     return Smith::object_effect(this).has_value() || Smith::object_activation(this).has_value();
383 }
384
385 /*!
386  * @brief オブジェクトがアーティファクトかを返す /
387  * Check if an object is artifact
388  * @return アーティファクトならばtrueを返す
389  */
390 bool ItemEntity::is_artifact() const
391 {
392     return this->is_fixed_artifact() || (this->art_name != 0);
393 }
394
395 /*!
396  * @brief オブジェクトが固定アーティファクトかを返す /
397  * Check if an object is fixed artifact
398  * @return 固定アーティファクトならばtrueを返す
399  */
400 bool ItemEntity::is_fixed_artifact() const
401 {
402     return !this->is_specific_artifact(FixedArtifactId::NONE);
403 }
404
405 /*!
406  * @brief オブジェクトがランダムアーティファクトかを返す /
407  * Check if an object is random artifact
408  * @return ランダムアーティファクトならばtrueを返す
409  */
410 bool ItemEntity::is_random_artifact() const
411 {
412     return this->is_artifact() && !this->is_fixed_artifact();
413 }
414
415 /*!
416  * @brief オブジェクトが通常のアイテム(アーティファクト、エゴ、鍛冶師エッセンス付加いずれでもない)かを返す /
417  * Check if an object is neither artifact, ego, nor 'smith' object
418  * @return 通常のアイテムならばtrueを返す
419  */
420 bool ItemEntity::is_nameless() const
421 {
422     return !this->is_artifact() && !this->is_ego() && !this->is_smith();
423 }
424
425 bool ItemEntity::is_valid() const
426 {
427     return this->k_idx != 0;
428 }
429
430 bool ItemEntity::is_broken() const
431 {
432     return any_bits(this->ident, IDENT_BROKEN);
433 }
434
435 bool ItemEntity::is_cursed() const
436 {
437     return this->curse_flags.any();
438 }
439
440 bool ItemEntity::is_held_by_monster() const
441 {
442     return this->held_m_idx != 0;
443 }
444
445 /*
446  * Determine if a given inventory item is "known"
447  * Test One -- Check for special "known" tag
448  * Test Two -- Check for "Easy Know" + "Aware"
449  */
450 bool ItemEntity::is_known() const
451 {
452     return any_bits(this->ident, IDENT_KNOWN) || (baseitems_info[this->k_idx].easy_know && baseitems_info[this->k_idx].aware);
453 }
454
455 bool ItemEntity::is_fully_known() const
456 {
457     return any_bits(this->ident, IDENT_FULL_KNOWN);
458 }
459
460 /*!
461  * @brief 与えられたオブジェクトのベースアイテムが鑑定済かを返す / Determine if a given inventory item is "aware"
462  * @return 鑑定済ならtrue
463  */
464 bool ItemEntity::is_aware() const
465 {
466     return baseitems_info[this->k_idx].aware;
467 }
468
469 /*
470  * Determine if a given inventory item is "tried"
471  */
472 bool ItemEntity::is_tried() const
473 {
474     return baseitems_info[this->k_idx].tried;
475 }
476
477 /*!
478  * @brief オブジェクトが薬であるかを返す
479  * @return オブジェクトが薬ならばtrueを返す
480  */
481 bool ItemEntity::is_potion() const
482 {
483     return baseitems_info[this->k_idx].bi_key.tval() == ItemKindType::POTION;
484 }
485
486 /*!
487  * @brief オブジェクトをプレイヤーが読むことができるかを判定する /
488  * Hook to determine if an object is readable
489  * @return 読むことが可能ならばtrueを返す
490  */
491 bool ItemEntity::is_readable() const
492 {
493     auto can_read = this->tval == ItemKindType::SCROLL;
494     can_read |= this->tval == ItemKindType::PARCHMENT;
495     can_read |= this->is_specific_artifact(FixedArtifactId::GHB);
496     can_read |= this->is_specific_artifact(FixedArtifactId::POWER);
497     return can_read;
498 }
499
500 /*!
501  * @brief オブジェクトがランタンの燃料になるかどうかを判定する
502  * An "item_tester_hook" for refilling lanterns
503  * @return オブジェクトがランタンの燃料になるならばTRUEを返す
504  */
505 bool ItemEntity::can_refill_lantern() const
506 {
507     return (this->tval == ItemKindType::FLASK) || ((this->tval == ItemKindType::LITE) && (this->sval == SV_LITE_LANTERN));
508 }
509
510 /*!
511  * @brief オブジェクトが松明に束ねられるかどうかを判定する
512  * An "item_tester_hook" for refilling torches
513  * @return オブジェクトが松明に束ねられるならばTRUEを返す
514  */
515 bool ItemEntity::can_refill_torch() const
516 {
517     return (this->tval == ItemKindType::LITE) && (this->sval == SV_LITE_TORCH);
518 }
519
520 /*!
521  * @brief 魔力充填が可能なアイテムかどうか判定する /
522  * Hook for "get_item()".  Determine if something is rechargable.
523  * @return 魔力充填が可能ならばTRUEを返す
524  */
525 bool ItemEntity::is_rechargeable() const
526 {
527     switch (this->tval) {
528     case ItemKindType::STAFF:
529     case ItemKindType::WAND:
530     case ItemKindType::ROD:
531         return true;
532     default:
533         return false;
534     }
535 }
536
537 /*!
538  * @brief 悪魔領域のグレーターデーモン召喚に利用可能な死体かどうかを返す。 / An "item_tester_hook" for offer
539  * @return 生贄に使用可能な死体ならばTRUEを返す。
540  */
541 bool ItemEntity::is_offerable() const
542 {
543     if ((this->tval != ItemKindType::CORPSE) || (this->sval != SV_CORPSE)) {
544         return false;
545     }
546
547     return angband_strchr("pht", monraces_info[i2enum<MonsterRaceId>(this->pval)].d_char) != nullptr;
548 }
549
550 /*!
551  * @brief オブジェクトをプレイヤーが魔道具として発動できるかを判定する /
552  * Hook to determine if an object is activatable
553  * @return 魔道具として発動可能ならばTRUEを返す
554  */
555 bool ItemEntity::is_activatable() const
556 {
557     if (!this->is_known()) {
558         return false;
559     }
560
561     auto flags = object_flags(this);
562     return flags.has(TR_ACTIVATE);
563 }
564
565 /*!
566  * @brief オブジェクトが燃料として使えるかを判定する
567  * @return 燃料か否か
568  */
569 bool ItemEntity::is_fuel() const
570 {
571     auto is_fuel = (this->tval == ItemKindType::LITE) && ((this->sval == SV_LITE_TORCH) || (this->sval == SV_LITE_LANTERN));
572     is_fuel |= (this->tval == ItemKindType::FLASK) && (this->sval == SV_FLASK_OIL);
573     return is_fuel;
574 }
575
576 /*!
577  * @brief オブジェクトが魔法書かどうかを判定する
578  * @return 魔法書か否か
579  */
580 bool ItemEntity::is_book() const
581 {
582     switch (this->tval) {
583     case ItemKindType::LIFE_BOOK:
584     case ItemKindType::SORCERY_BOOK:
585     case ItemKindType::NATURE_BOOK:
586     case ItemKindType::CHAOS_BOOK:
587     case ItemKindType::DEATH_BOOK:
588     case ItemKindType::TRUMP_BOOK:
589     case ItemKindType::ARCANE_BOOK:
590     case ItemKindType::CRAFT_BOOK:
591     case ItemKindType::DEMON_BOOK:
592     case ItemKindType::CRUSADE_BOOK:
593     case ItemKindType::MUSIC_BOOK:
594     case ItemKindType::HISSATSU_BOOK:
595     case ItemKindType::HEX_BOOK:
596         return true;
597     default:
598         return false;
599     }
600 }
601
602 /*!
603  * @brief オブジェクトが同一の命中値上昇及びダメージ上昇があるかを判定する
604  * @return 同一修正か
605  * @details 鍛冶師が篭手に殺戮エッセンスを付加した場合のみこの判定に意味がある
606  */
607 bool ItemEntity::is_glove_same_temper(const ItemEntity *j_ptr) const
608 {
609     if (!this->is_smith() || !j_ptr->is_smith()) {
610         return false;
611     }
612
613     if (this->smith_hit != j_ptr->smith_hit) {
614         return true;
615     }
616
617     if (this->smith_damage != j_ptr->smith_damage) {
618         return true;
619     }
620
621     return false;
622 }
623
624 /*!
625  * @brief オブジェクトが「2つの~~」と重ねられるかを一般的に判定する
626  * @return 重ねられるか
627  * @details 個別のアイテムによっては別途条件があるが、それはこの関数では判定しない
628  */
629 bool ItemEntity::can_pile(const ItemEntity *j_ptr) const
630 {
631     if (this->is_known() != j_ptr->is_known()) {
632         return false;
633     }
634
635     if (this->feeling != j_ptr->feeling) {
636         return false;
637     }
638
639     if (this->to_h != j_ptr->to_h) {
640         return false;
641     }
642
643     if (this->to_d != j_ptr->to_d) {
644         return false;
645     }
646
647     if (this->to_a != j_ptr->to_a) {
648         return false;
649     }
650
651     if (this->pval != j_ptr->pval) {
652         return false;
653     }
654
655     if (this->is_artifact() || j_ptr->is_artifact()) {
656         return false;
657     }
658
659     if (this->ego_idx != j_ptr->ego_idx) {
660         return false;
661     }
662
663     if (this->timeout || j_ptr->timeout) {
664         return false;
665     }
666
667     if (this->ac != j_ptr->ac) {
668         return false;
669     }
670
671     if (this->dd != j_ptr->dd) {
672         return false;
673     }
674
675     if (this->ds != j_ptr->ds) {
676         return false;
677     }
678
679     if (Smith::object_effect(this) != Smith::object_effect(j_ptr)) {
680         return false;
681     }
682
683     if (Smith::object_activation(this) != Smith::object_activation(j_ptr)) {
684         return false;
685     }
686
687     return true;
688 }
689
690 /*
691  * @brief アイテムの色を取得する
692  * @details 未鑑定名のあるアイテム (薬等)は、未鑑定名の割り当てられた色を返す
693  * 未鑑定名のないアイテム (魔法書等)はベースアイテム定義そのままを返す
694  * その中でモンスターの死体以外は、ベースアイテムの色を返す
695  * モンスターの死体は、元モンスターの色を返す
696  * 異常アイテム (「何か」)の場合、ベースアイテム定義に基づき黒を返す
697  */
698 TERM_COLOR ItemEntity::get_color() const
699 {
700     const auto &base_item = baseitems_info[this->k_idx];
701     const auto flavor = base_item.flavor;
702     if (flavor != 0) {
703         return baseitems_info[flavor].x_attr;
704     }
705
706     auto has_attr = this->k_idx == 0;
707     has_attr |= (this->tval != ItemKindType::CORPSE) || (this->sval != SV_CORPSE);
708     has_attr |= base_item.x_attr != TERM_DARK;
709     if (has_attr) {
710         return base_item.x_attr;
711     }
712
713     return monraces_info[i2enum<MonsterRaceId>(this->pval)].x_attr;
714 }
715
716 /*
717  * @brief アイテムシンボルを取得する
718  * @details 未鑑定名のないアイテム (魔法書等)はベースアイテム定義そのまま
719  * 未鑑定名のあるアイテム (薬等)は、未鑑定名の割り当てられたシンボル
720  * @todo 色と違って変える必要はない……はず?
721  */
722 char ItemEntity::get_symbol() const
723 {
724     const auto &base_item = baseitems_info[this->k_idx];
725     const auto flavor = base_item.flavor;
726     return flavor ? baseitems_info[flavor].x_char : base_item.x_char;
727 }
728
729 /*!
730  * @brief オブジェクト価格算出のメインルーチン
731  * @return オブジェクトの判明している現価格
732  */
733 int ItemEntity::get_price() const
734 {
735     int value;
736     const auto is_worthless = this->is_broken() || this->is_cursed();
737     if (this->is_known()) {
738         if (is_worthless) {
739             return 0;
740         }
741
742         value = object_value_real(this);
743     } else {
744         if (any_bits(this->ident, IDENT_SENSE) && is_worthless) {
745             return 0;
746         }
747
748         value = this->get_baseitem_price();
749     }
750
751     if (this->discount) {
752         value -= (value * this->discount / 100L);
753     }
754
755     return value;
756 }
757
758 /*!
759  * @brief 未鑑定なベースアイテムの基本価格を返す
760  * @return オブジェクトの未鑑定価格
761  */
762 int ItemEntity::get_baseitem_price() const
763 {
764     if (this->is_aware()) {
765         return baseitems_info[this->k_idx].cost;
766     }
767
768     switch (this->tval) {
769     case ItemKindType::FOOD:
770         return 5;
771     case ItemKindType::POTION:
772     case ItemKindType::SCROLL:
773         return 20;
774     case ItemKindType::STAFF:
775         return 70;
776     case ItemKindType::WAND:
777         return 50;
778     case ItemKindType::ROD:
779         return 90;
780     case ItemKindType::RING:
781     case ItemKindType::AMULET:
782         return 45;
783     case ItemKindType::FIGURINE:
784         return this->calc_figurine_value();
785     case ItemKindType::CAPTURE:
786         return this->calc_capture_value();
787     default:
788         return 0;
789     }
790 }
791
792 int ItemEntity::calc_figurine_value() const
793 {
794     auto figure_r_idx = i2enum<MonsterRaceId>(this->pval);
795     auto level = monraces_info[figure_r_idx].level;
796     if (level < 20) {
797         return level * 50L;
798     }
799
800     if (level < 30) {
801         return 1000 + (level - 20) * 150;
802     }
803
804     if (level < 40) {
805         return 2500 + (level - 30) * 350;
806     }
807
808     if (level < 50) {
809         return 6000 + (level - 40) * 800;
810     }
811
812     return 14000 + (level - 50) * 2000;
813 }
814
815 int ItemEntity::calc_capture_value() const
816 {
817     auto capture_r_idx = i2enum<MonsterRaceId>(this->pval);
818     if (!MonsterRace(capture_r_idx).is_valid()) {
819         return 1000;
820     }
821
822     return (monraces_info[capture_r_idx].level) * 50 + 1000;
823 }
824
825 bool ItemEntity::is_specific_artifact(FixedArtifactId id) const
826 {
827     return this->fixed_artifact_idx == id;
828 }