OSDN Git Service

[Refactor] #2124 Changed struct object_type to class ObjectType
[hengbandforosx/hengbandosx.git] / src / market / building-craft-fix.cpp
1 #include "market/building-craft-fix.h"
2 #include "artifact/random-art-effects.h"
3 #include "artifact/fixed-art-types.h"
4 #include "artifact/artifact-info.h"
5 #include "core/asking-player.h"
6 #include "core/player-update-types.h"
7 #include "core/stuff-handler.h"
8 #include "flavor/flavor-describer.h"
9 #include "flavor/object-flavor-types.h"
10 #include "floor/floor-object.h"
11 #include "inventory/inventory-object.h"
12 #include "market/building-util.h"
13 #include "object-enchant/object-boost.h"
14 #include "object-enchant/special-object-flags.h"
15 #include "object-enchant/tr-types.h"
16 #include "object-hook/hook-weapon.h"
17 #include "object/item-tester-hooker.h"
18 #include "object/item-use-flags.h"
19 #include "object/object-flags.h"
20 #include "object/object-kind-hook.h"
21 #include "object/object-kind.h"
22 #include "object/object-value.h"
23 #include "racial/racial-android.h"
24 #include "spell-realm/spells-hex.h"
25 #include "sv-definition/sv-other-types.h"
26 #include "sv-definition/sv-weapon-types.h"
27 #include "system/object-type-definition.h"
28 #include "system/player-type-definition.h"
29 #include "term/screen-processor.h"
30 #include "util/bit-flags-calculator.h"
31 #include "view/display-messages.h"
32
33 /*!
34  * @brief 修復材料のオブジェクトから修復対象に特性を移植する。
35  * @param to_ptr 修復対象オブジェクトの構造体の参照ポインタ。
36  * @param from_ptr 修復材料オブジェクトの構造体の参照ポインタ。
37  * @return 修復対象になるならTRUEを返す。
38  */
39 static void give_one_ability_of_object(ObjectType *to_ptr, ObjectType *from_ptr)
40 {
41     auto to_flgs = object_flags(to_ptr);
42     auto from_flgs = object_flags(from_ptr);
43
44     int n = 0;
45     tr_type cand[TR_FLAG_MAX];
46     for (int i = 0; i < TR_FLAG_MAX; i++) {
47         switch (i) {
48         case TR_IGNORE_ACID:
49         case TR_IGNORE_ELEC:
50         case TR_IGNORE_FIRE:
51         case TR_IGNORE_COLD:
52         case TR_ACTIVATE:
53         case TR_RIDING:
54         case TR_THROW:
55         case TR_SHOW_MODS:
56         case TR_HIDE_TYPE:
57         case TR_XXX_93:
58         case TR_XXX_94:
59         case TR_FULL_NAME:
60         case TR_FIXED_FLAVOR:
61             break;
62         default:
63             auto tr_flag = i2enum<tr_type>(i);
64             if (from_flgs.has(tr_flag) && to_flgs.has_not(tr_flag)) {
65                 if (!(TR_PVAL_FLAG_MASK.has(tr_flag) && (from_ptr->pval < 1)))
66                     cand[n++] = tr_flag;
67             }
68         }
69     }
70
71     if (n <= 0)
72         return;
73
74     auto tr_idx = cand[randint0(n)];
75     to_ptr->art_flags.set(tr_idx);
76     if (TR_PVAL_FLAG_MASK.has(tr_idx))
77         to_ptr->pval = std::max<short>(to_ptr->pval, 1);
78     auto bmax = std::min<short>(3, std::max<short>(1, 40 / (to_ptr->dd * to_ptr->ds)));
79     if (tr_idx == TR_BLOWS)
80         to_ptr->pval = std::min<short>(to_ptr->pval, bmax);
81     if (tr_idx == TR_SPEED)
82         to_ptr->pval = std::min<short>(to_ptr->pval, 4);
83 }
84
85 /*!
86  * @brief アイテム修復処理のメインルーチン / Repair broken weapon
87  * @param player_ptr プレイヤーへの参照ポインタ
88  * @param bcost 基本修復費用
89  * @return 実際にかかった費用
90  */
91 static PRICE repair_broken_weapon_aux(PlayerType *player_ptr, PRICE bcost)
92 {
93     clear_bldg(0, 22);
94     int row = 7;
95     prt(_("修復には材料となるもう1つの武器が必要です。", "Hand one material weapon to repair a broken weapon."), row, 2);
96     prt(_("材料に使用した武器はなくなります!", "The material weapon will disappear after repairing!!"), row + 1, 2);
97
98     concptr q = _("どの折れた武器を修復しますか?", "Repair which broken weapon? ");
99     concptr s = _("修復できる折れた武器がありません。", "You have no broken weapon to repair.");
100
101     OBJECT_IDX item;
102     ObjectType *o_ptr;
103     o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_EQUIP), FuncItemTester(&ObjectType::is_broken_weapon));
104     if (!o_ptr)
105         return 0;
106
107     if (!o_ptr->is_ego() && !o_ptr->is_artifact()) {
108         msg_format(_("それは直してもしょうがないぜ。", "It is worthless to repair."));
109         return 0;
110     }
111
112     if (o_ptr->number > 1) {
113         msg_format(_("一度に複数を修復することはできません!", "They are too many to repair at once!"));
114         return 0;
115     }
116
117     char basenm[MAX_NLEN];
118     describe_flavor(player_ptr, basenm, o_ptr, OD_NAME_ONLY);
119     prt(format(_("修復する武器 : %s", "Repairing: %s"), basenm), row + 3, 2);
120
121     q = _("材料となる武器は?", "Which weapon for material? ");
122     s = _("材料となる武器がありません。", "You have no material for the repair.");
123
124     OBJECT_IDX mater;
125     ObjectType *mo_ptr;
126     mo_ptr = choose_object(player_ptr, &mater, q, s, (USE_INVEN | USE_EQUIP), FuncItemTester(&ObjectType::is_orthodox_melee_weapons));
127     if (!mo_ptr)
128         return 0;
129     if (mater == item) {
130         msg_print(_("クラインの壷じゃない!", "This is not a Klein bottle!"));
131         return 0;
132     }
133
134     describe_flavor(player_ptr, basenm, mo_ptr, OD_NAME_ONLY);
135     prt(format(_("材料とする武器: %s", "Material : %s"), basenm), row + 4, 2);
136     PRICE cost = bcost + object_value_real(o_ptr) * 2;
137     if (!get_check(format(_("$%dかかりますがよろしいですか? ", "Costs %d gold, okay? "), cost)))
138         return 0;
139
140     if (player_ptr->au < cost) {
141         describe_flavor(player_ptr, basenm, o_ptr, OD_NAME_ONLY);
142         msg_format(_("%sを修復するだけのゴールドがありません!", "You do not have the gold to repair %s!"), basenm);
143         msg_print(nullptr);
144         return 0;
145     }
146
147     KIND_OBJECT_IDX k_idx;
148     if (o_ptr->sval == SV_BROKEN_DAGGER) {
149         int n = 1;
150         k_idx = 0;
151         for (const auto &k_ref : k_info) {
152             if (k_ref.tval != ItemKindType::SWORD)
153                 continue;
154             if ((k_ref.sval == SV_BROKEN_DAGGER) || (k_ref.sval == SV_BROKEN_SWORD) || (k_ref.sval == SV_POISON_NEEDLE))
155                 continue;
156             if (k_ref.weight > 99)
157                 continue;
158
159             if (one_in_(n)) {
160                 k_idx = k_ref.idx;
161                 n++;
162             }
163         }
164     } else {
165         auto tval = (one_in_(5) ? mo_ptr->tval : ItemKindType::SWORD);
166         while (true) {
167             object_kind *ck_ptr;
168             k_idx = lookup_kind(tval, SV_ANY);
169             ck_ptr = &k_info[k_idx];
170
171             if (tval == ItemKindType::SWORD) {
172                 if ((ck_ptr->sval == SV_BROKEN_DAGGER) || (ck_ptr->sval == SV_BROKEN_SWORD) || (ck_ptr->sval == SV_DIAMOND_EDGE)
173                     || (ck_ptr->sval == SV_POISON_NEEDLE))
174                     continue;
175             }
176             if (tval == ItemKindType::POLEARM) {
177                 if ((ck_ptr->sval == SV_DEATH_SCYTHE) || (ck_ptr->sval == SV_TSURIZAO))
178                     continue;
179             }
180             if (tval == ItemKindType::HAFTED) {
181                 if ((ck_ptr->sval == SV_GROND) || (ck_ptr->sval == SV_WIZSTAFF) || (ck_ptr->sval == SV_NAMAKE_HAMMER))
182                     continue;
183             }
184
185             break;
186         }
187     }
188
189     int dd_bonus = o_ptr->dd - k_info[o_ptr->k_idx].dd;
190     int ds_bonus = o_ptr->ds - k_info[o_ptr->k_idx].ds;
191     dd_bonus += mo_ptr->dd - k_info[mo_ptr->k_idx].dd;
192     ds_bonus += mo_ptr->ds - k_info[mo_ptr->k_idx].ds;
193
194     object_kind *k_ptr;
195     k_ptr = &k_info[k_idx];
196     o_ptr->k_idx = k_idx;
197     o_ptr->weight = k_ptr->weight;
198     o_ptr->tval = k_ptr->tval;
199     o_ptr->sval = k_ptr->sval;
200     o_ptr->dd = k_ptr->dd;
201     o_ptr->ds = k_ptr->ds;
202
203     o_ptr->art_flags.set(k_ptr->flags);
204
205     if (k_ptr->pval)
206         o_ptr->pval = std::max<short>(o_ptr->pval, randint1(k_ptr->pval));
207     if (k_ptr->flags.has(TR_ACTIVATE))
208         o_ptr->activation_id = k_ptr->act_idx;
209
210     if (dd_bonus > 0) {
211         o_ptr->dd++;
212         for (int i = 1; i < dd_bonus; i++) {
213             if (one_in_(o_ptr->dd + i))
214                 o_ptr->dd++;
215         }
216     }
217
218     if (ds_bonus > 0) {
219         o_ptr->ds++;
220         for (int i = 1; i < ds_bonus; i++) {
221             if (one_in_(o_ptr->ds + i))
222                 o_ptr->ds++;
223         }
224     }
225
226     if (k_ptr->flags.has(TR_BLOWS)) {
227         auto bmax = std::min<short>(3, std::max<short>(1, 40 / (o_ptr->dd * o_ptr->ds)));
228         o_ptr->pval = std::min<short>(o_ptr->pval, bmax);
229     }
230
231     give_one_ability_of_object(o_ptr, mo_ptr);
232     o_ptr->to_d += std::max(0, (mo_ptr->to_d / 3));
233     o_ptr->to_h += std::max<short>(0, (mo_ptr->to_h / 3));
234     o_ptr->to_a += std::max<short>(0, (mo_ptr->to_a));
235
236     if ((o_ptr->name1 == ART_NARSIL) || (o_ptr->is_random_artifact() && one_in_(1)) || (o_ptr->is_ego() && one_in_(7))) {
237         if (o_ptr->is_ego()) {
238             o_ptr->art_flags.set(TR_IGNORE_FIRE);
239             o_ptr->art_flags.set(TR_IGNORE_ACID);
240         }
241
242         give_one_ability_of_object(o_ptr, mo_ptr);
243         if (activation_index(o_ptr) == RandomArtActType::NONE)
244             one_activation(o_ptr);
245
246         if (o_ptr->name1 == ART_NARSIL) {
247             one_high_resistance(o_ptr);
248             one_ability(o_ptr);
249         }
250
251         msg_print(_("これはかなりの業物だったようだ。", "This blade seems to be exceptional."));
252     }
253
254     describe_flavor(player_ptr, basenm, o_ptr, OD_NAME_ONLY);
255 #ifdef JP
256     msg_format("$%dで%sに修復しました。", cost, basenm);
257 #else
258     msg_format("Repaired into %s for %d gold.", basenm, cost);
259 #endif
260     msg_print(nullptr);
261     o_ptr->ident &= ~(IDENT_BROKEN);
262     o_ptr->discount = 99;
263
264     calc_android_exp(player_ptr);
265     inven_item_increase(player_ptr, mater, -1);
266     inven_item_optimize(player_ptr, mater);
267
268     player_ptr->update |= PU_BONUS;
269     handle_stuff(player_ptr);
270     return (cost);
271 }
272
273 /*!
274  * @brief アイテム修復処理の過渡ルーチン / Repair broken weapon
275  * @param player_ptr プレイヤーへの参照ポインタ
276  * @param bcost 基本鑑定費用
277  * @return 実際にかかった費用
278  */
279 int repair_broken_weapon(PlayerType *player_ptr, PRICE bcost)
280 {
281     PRICE cost;
282     screen_save();
283     cost = repair_broken_weapon_aux(player_ptr, bcost);
284     screen_load();
285     return cost;
286 }