OSDN Git Service

Merge pull request #3591 from sikabane-works/release/3.0.0.89-Alpha
[hengbandforosx/hengbandosx.git] / src / wizard / items-spoiler.cpp
1 #include "wizard/items-spoiler.h"
2 #include "flavor/flavor-describer.h"
3 #include "flavor/object-flavor-types.h"
4 #include "io/files-util.h"
5 #include "object-enchant/special-object-flags.h"
6 #include "object-enchant/trg-types.h"
7 #include "object/object-value.h"
8 #include "system/angband-version.h"
9 #include "system/baseitem-info.h"
10 #include "system/item-entity.h"
11 #include "system/player-type-definition.h"
12 #include "term/z-form.h"
13 #include "util/angband-files.h"
14 #include "view/display-messages.h"
15 #include "wizard/spoiler-util.h"
16 #include <algorithm>
17 #include <sstream>
18
19 /*!
20  * @brief アイテムの生成階層と価格を得る
21  *
22  * @param item アイテム
23  * @return 階層と価格のペア
24  */
25 static std::pair<DEPTH, PRICE> get_info(const ItemEntity &item)
26 {
27     const auto level = item.get_baseitem().level;
28     const auto price = item.get_price();
29     return { level, price };
30 }
31
32 /*!
33  * @brief アイテムのダメージもしくはACの文字列表記を得る
34  *
35  * @param item アイテム
36  * @return ダメージもしくはACの文字列表記
37  */
38 static std::string describe_dam_or_ac(const ItemEntity &item)
39 {
40     switch (item.bi_key.tval()) {
41     case ItemKindType::SHOT:
42     case ItemKindType::BOLT:
43     case ItemKindType::ARROW:
44         return format("%dd%d", item.dd, item.ds);
45     case ItemKindType::HAFTED:
46     case ItemKindType::POLEARM:
47     case ItemKindType::SWORD:
48     case ItemKindType::DIGGING:
49         return format("%dd%d", item.dd, item.ds);
50     case ItemKindType::BOOTS:
51     case ItemKindType::GLOVES:
52     case ItemKindType::CLOAK:
53     case ItemKindType::CROWN:
54     case ItemKindType::HELM:
55     case ItemKindType::SHIELD:
56     case ItemKindType::SOFT_ARMOR:
57     case ItemKindType::HARD_ARMOR:
58     case ItemKindType::DRAG_ARMOR:
59         return format("%d", item.ac);
60     default:
61         return {};
62     }
63 }
64
65 /*!
66  * @brief アイテムの生成確率の文字列表記を得る
67  *
68  * @param item アイテム
69  * @return 生成確率の文字列表記
70  */
71 static std::string describe_chance(const ItemEntity &item)
72 {
73     std::stringstream ss;
74
75     const auto &baseitem = item.get_baseitem();
76     for (auto i = 0U; i < baseitem.alloc_tables.size(); i++) {
77         const auto &[level, chance] = baseitem.alloc_tables[i];
78         if (chance > 0) {
79             ss << format("%s%3dF:%+4d", (i != 0 ? "/" : ""), level, 100 / chance);
80         }
81     }
82
83     return ss.str();
84 }
85
86 /*!
87  * @brief アイテムの重量の文字列表記を得る
88  *
89  * @param item アイテム
90  * @return アイテムの重量の文字列表記
91  */
92 static std::string describe_weight(const ItemEntity &item)
93 {
94     return format("%3d.%d", (int)(item.weight / 10), (int)(item.weight % 10));
95 }
96
97 /*!
98  * @brief obj-desc.txt出力用にベースアイテムIDからItemEntityオブジェクトを生成する
99  *
100  * @param bi_id ベースアイテムID
101  * @return obj-desc.txt出力用に使用するItemEntityオブジェクト
102  */
103 static ItemEntity prepare_item_for_obj_desc(short bi_id)
104 {
105     ItemEntity item;
106     item.prep(bi_id);
107     item.ident |= IDENT_KNOWN;
108     item.pval = 0;
109     item.to_a = 0;
110     item.to_h = 0;
111     item.to_d = 0;
112     return item;
113 }
114
115 /*!
116  * @brief 各ベースアイテムの情報を一行毎に記述する
117  */
118 SpoilerOutputResultType spoil_obj_desc()
119 {
120     const auto &path = path_build(ANGBAND_DIR_USER, "obj-desc.txt");
121     std::ofstream ofs(path);
122     if (!ofs) {
123         return SpoilerOutputResultType::FILE_OPEN_FAILED;
124     }
125
126     ofs << format("Spoiler File -- Basic Items (%s)\n\n\n", get_version().data());
127     ofs << format("%-37s%8s%7s%5s %40s%9s\n", "Description", "Dam/AC", "Wgt", "Lev", "Chance", "Cost");
128     ofs << format("%-37s%8s%7s%5s %40s%9s\n", "-------------------------------------", "------", "---", "---", "----------------", "----");
129
130     for (const auto &[tval_list, name] : group_item_list) {
131         std::vector<short> whats;
132         for (auto tval : tval_list) {
133             for (const auto &baseitem : baseitems_info) {
134                 if ((baseitem.bi_key.tval() == tval) && baseitem.gen_flags.has_not(ItemGenerationTraitType::INSTA_ART)) {
135                     whats.push_back(baseitem.idx);
136                 }
137             }
138         }
139         if (whats.empty()) {
140             continue;
141         }
142
143         std::stable_sort(whats.begin(), whats.end(), [](auto bi_id1, auto bi_id2) {
144             const auto item1 = prepare_item_for_obj_desc(bi_id1);
145             const auto item2 = prepare_item_for_obj_desc(bi_id2);
146             const auto [depth1, price1] = get_info(item1);
147             const auto [depth2, price2] = get_info(item2);
148             return (price1 != price2) ? price1 < price2 : depth1 < depth2;
149         });
150
151         ofs << "\n\n"
152             << name << "\n\n";
153         for (const auto &bi_id : whats) {
154             PlayerType dummy;
155             const auto item = prepare_item_for_obj_desc(bi_id);
156             const auto item_name = describe_flavor(&dummy, &item, OD_NAME_ONLY | OD_STORE);
157             const auto [depth, price] = get_info(item);
158             const auto dam_or_ac = describe_dam_or_ac(item);
159             const auto weight = describe_weight(item);
160             const auto chance = describe_chance(item);
161             ofs << format("  %-35s%8s%7s%5d %-40s%9d\n", item_name.data(), dam_or_ac.data(), weight.data(), depth, chance.data(), price);
162         }
163     }
164
165     return ofs.good() ? SpoilerOutputResultType::SUCCESSFUL : SpoilerOutputResultType::FILE_CLOSE_FAILED;
166 }