OSDN Git Service

[Refactor] #2844 *k_ptr/&k_ref を&baseitem に差し替えた (一部flavor周りで残りアリ)
[hengbandforosx/hengbandosx.git] / src / artifact / random-art-generator.cpp
1 /*!
2  * @file random-art-generator.cpp
3  * @brief ランダムアーティファクトの生成メイン定義 / Artifact code
4  * @date 2020/07/14
5  * @author Hourier
6  */
7
8 #include "artifact/random-art-generator.h"
9 #include "artifact/fixed-art-types.h"
10 #include "artifact/random-art-activation.h"
11 #include "artifact/random-art-bias-types.h"
12 #include "artifact/random-art-characteristics.h"
13 #include "artifact/random-art-effects.h"
14 #include "artifact/random-art-misc.h"
15 #include "artifact/random-art-pval-investor.h"
16 #include "artifact/random-art-resistance.h"
17 #include "artifact/random-art-slay.h"
18 #include "avatar/avatar.h"
19 #include "core/asking-player.h"
20 #include "core/window-redrawer.h"
21 #include "flavor/object-flavor.h"
22 #include "game-option/cheat-types.h"
23 #include "object-enchant/special-object-flags.h"
24 #include "object-enchant/tr-types.h"
25 #include "object-hook/hook-armor.h"
26 #include "object-hook/hook-weapon.h"
27 #include "object/object-flags.h"
28 #include "object/object-kind-hook.h"
29 #include "object/object-value-calc.h"
30 #include "object/tval-types.h"
31 #include "perception/identification.h"
32 #include "perception/object-perception.h"
33 #include "sv-definition/sv-weapon-types.h"
34 #include "system/baseitem-info.h"
35 #include "system/item-entity.h"
36 #include "system/player-type-definition.h"
37 #include "util/bit-flags-calculator.h"
38 #include "util/quarks.h"
39 #include "view/display-messages.h"
40 #include "wizard/artifact-bias-table.h"
41 #include "wizard/wizard-messages.h"
42 #include "world/world.h"
43
44 static bool weakening_artifact(ItemEntity *o_ptr)
45 {
46     const auto bi_id = lookup_baseitem_id(o_ptr->bi_key);
47     const auto &baseitem = baseitems_info[bi_id];
48     auto flgs = object_flags(o_ptr);
49
50     if (flgs.has(TR_KILL_EVIL)) {
51         o_ptr->art_flags.reset(TR_KILL_EVIL);
52         o_ptr->art_flags.set(TR_SLAY_EVIL);
53         return true;
54     }
55
56     if (baseitem.dd < o_ptr->dd) {
57         o_ptr->dd--;
58         return true;
59     }
60
61     if (baseitem.ds < o_ptr->ds) {
62         o_ptr->ds--;
63         return true;
64     }
65
66     if (o_ptr->to_d > 10) {
67         o_ptr->to_d = o_ptr->to_d - damroll(1, 6);
68         if (o_ptr->to_d < 10) {
69             o_ptr->to_d = 10;
70         }
71
72         return true;
73     }
74
75     return false;
76 }
77
78 static void set_artifact_bias(PlayerType *player_ptr, ItemEntity *o_ptr, int *warrior_artifact_bias)
79 {
80     switch (player_ptr->pclass) {
81     case PlayerClassType::WARRIOR:
82     case PlayerClassType::BERSERKER:
83     case PlayerClassType::ARCHER:
84     case PlayerClassType::SAMURAI:
85     case PlayerClassType::CAVALRY:
86     case PlayerClassType::SMITH:
87         o_ptr->artifact_bias = BIAS_WARRIOR;
88         break;
89     case PlayerClassType::MAGE:
90     case PlayerClassType::HIGH_MAGE:
91     case PlayerClassType::SORCERER:
92     case PlayerClassType::MAGIC_EATER:
93     case PlayerClassType::BLUE_MAGE:
94         o_ptr->artifact_bias = BIAS_MAGE;
95         break;
96     case PlayerClassType::PRIEST:
97         o_ptr->artifact_bias = BIAS_PRIESTLY;
98         break;
99     case PlayerClassType::ROGUE:
100     case PlayerClassType::NINJA:
101         o_ptr->artifact_bias = BIAS_ROGUE;
102         *warrior_artifact_bias = 25;
103         break;
104     case PlayerClassType::RANGER:
105     case PlayerClassType::SNIPER:
106         o_ptr->artifact_bias = BIAS_RANGER;
107         *warrior_artifact_bias = 30;
108         break;
109     case PlayerClassType::PALADIN:
110         o_ptr->artifact_bias = BIAS_PRIESTLY;
111         *warrior_artifact_bias = 40;
112         break;
113     case PlayerClassType::WARRIOR_MAGE:
114     case PlayerClassType::RED_MAGE:
115         o_ptr->artifact_bias = BIAS_MAGE;
116         *warrior_artifact_bias = 40;
117         break;
118     case PlayerClassType::CHAOS_WARRIOR:
119         o_ptr->artifact_bias = BIAS_CHAOS;
120         *warrior_artifact_bias = 40;
121         break;
122     case PlayerClassType::MONK:
123     case PlayerClassType::FORCETRAINER:
124         o_ptr->artifact_bias = BIAS_PRIESTLY;
125         break;
126     case PlayerClassType::MINDCRAFTER:
127     case PlayerClassType::BARD:
128         if (randint1(5) > 2) {
129             o_ptr->artifact_bias = BIAS_PRIESTLY;
130         }
131         break;
132     case PlayerClassType::TOURIST:
133         if (randint1(5) > 2) {
134             o_ptr->artifact_bias = BIAS_WARRIOR;
135         }
136         break;
137     case PlayerClassType::IMITATOR:
138         if (randint1(2) > 1) {
139             o_ptr->artifact_bias = BIAS_RANGER;
140         }
141         break;
142     case PlayerClassType::BEASTMASTER:
143         o_ptr->artifact_bias = BIAS_CHR;
144         *warrior_artifact_bias = 50;
145         break;
146     case PlayerClassType::MIRROR_MASTER:
147         if (randint1(4) > 1) {
148             o_ptr->artifact_bias = BIAS_MAGE;
149         } else {
150             o_ptr->artifact_bias = BIAS_ROGUE;
151         }
152         break;
153     case PlayerClassType::ELEMENTALIST:
154         o_ptr->artifact_bias = one_in_(2) ? BIAS_MAGE : BIAS_INT;
155         break;
156
157     case PlayerClassType::MAX:
158         break;
159     }
160 }
161
162 static void decide_warrior_bias(PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll)
163 {
164     int warrior_artifact_bias = 0;
165     if (a_scroll && one_in_(4)) {
166         set_artifact_bias(player_ptr, o_ptr, &warrior_artifact_bias);
167     }
168
169     if (a_scroll && (randint1(100) <= warrior_artifact_bias)) {
170         o_ptr->artifact_bias = BIAS_WARRIOR;
171     }
172 }
173
174 static bool decide_random_art_cursed(const bool a_scroll, ItemEntity *o_ptr)
175 {
176     constexpr auto chance_cursed = 13;
177     if (!a_scroll && one_in_(chance_cursed)) {
178         return true;
179     }
180
181     const auto tval = o_ptr->bi_key.tval();
182     if (((tval == ItemKindType::AMULET) || (tval == ItemKindType::RING)) && o_ptr->is_cursed()) {
183         return true;
184     }
185
186     return false;
187 }
188
189 static int decide_random_art_power(const bool a_cursed)
190 {
191     int powers = randint1(5) + 1;
192     while (one_in_(powers) || one_in_(7) || one_in_(10)) {
193         powers++;
194     }
195
196     if (!a_cursed && one_in_(CHANCE_STRENGTHENING)) {
197         powers *= 2;
198     }
199
200     if (a_cursed) {
201         powers /= 2;
202     }
203
204     return powers;
205 }
206
207 static void invest_powers(PlayerType *player_ptr, ItemEntity *o_ptr, int *powers, bool *has_pval, const bool a_cursed)
208 {
209     int max_type = o_ptr->is_weapon_ammo() ? 7 : 5;
210     while ((*powers)--) {
211         switch (randint1(max_type)) {
212         case 1:
213         case 2:
214             random_plus(o_ptr);
215             *has_pval = true;
216             break;
217         case 3:
218         case 4:
219             if (one_in_(2) && o_ptr->is_weapon_ammo() && (o_ptr->bi_key.tval() != ItemKindType::BOW)) {
220                 if (a_cursed && !one_in_(13)) {
221                     break;
222                 }
223                 if (one_in_(13)) {
224                     if (one_in_(o_ptr->ds + 4)) {
225                         o_ptr->ds++;
226                     }
227                 } else {
228                     if (one_in_(o_ptr->dd + 1)) {
229                         o_ptr->dd++;
230                     }
231                 }
232             } else {
233                 random_resistance(o_ptr);
234             }
235
236             break;
237         case 5:
238             random_misc(player_ptr, o_ptr);
239             break;
240         case 6:
241         case 7:
242             random_slay(o_ptr);
243             break;
244         default:
245             if (w_ptr->wizard) {
246                 msg_print("Switch error in become_random_artifact!");
247             }
248
249             (*powers)++;
250         }
251     };
252 }
253
254 static void strengthen_pval(ItemEntity *o_ptr)
255 {
256     if (o_ptr->art_flags.has(TR_BLOWS)) {
257         o_ptr->pval = randint1(2);
258         if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_HAYABUSA)) {
259             o_ptr->pval++;
260         }
261     } else {
262         do {
263             o_ptr->pval++;
264         } while (o_ptr->pval < randint1(5) || one_in_(o_ptr->pval));
265     }
266
267     if ((o_ptr->pval > 4) && !one_in_(CHANCE_STRENGTHENING)) {
268         o_ptr->pval = 4;
269     }
270 }
271
272 /*!
273  * @brief 防具ならばAC修正、武具なら殺戮修正を付与する
274  * @param player_ptr プレイヤーへの参照ポインタ
275  * @param o_ptr ランダムアーティファクトを示すアイテムへの参照ポインタ
276  */
277 static void invest_positive_modified_value(ItemEntity *o_ptr)
278 {
279     if (o_ptr->is_protector()) {
280         o_ptr->to_a += randint1(o_ptr->to_a > 19 ? 1 : 20 - o_ptr->to_a);
281         return;
282     }
283
284     if (!o_ptr->is_weapon_ammo()) {
285         return;
286     }
287
288     o_ptr->to_h += randint1(o_ptr->to_h > 19 ? 1 : 20 - o_ptr->to_h);
289     o_ptr->to_d += randint1(o_ptr->to_d > 19 ? 1 : 20 - o_ptr->to_d);
290     if ((o_ptr->art_flags.has(TR_WIS)) && (o_ptr->pval > 0)) {
291         o_ptr->art_flags.set(TR_BLESSED);
292     }
293 }
294
295 /*!
296  * @brief 防具のAC修正が高すぎた場合に弱化させる
297  * @param player_ptr プレイヤーへの参照ポインタ
298  * @param o_ptr ランダムアーティファクトを示すアイテムへの参照ポインタ
299  */
300 static void invest_negative_modified_value(ItemEntity *o_ptr)
301 {
302     if (!o_ptr->is_protector()) {
303         return;
304     }
305
306     while ((o_ptr->to_d + o_ptr->to_h) > 20) {
307         if (one_in_(o_ptr->to_d) && one_in_(o_ptr->to_h)) {
308             break;
309         }
310
311         o_ptr->to_d -= (int)randint0(3);
312         o_ptr->to_h -= (HIT_PROB)randint0(3);
313     }
314
315     while ((o_ptr->to_d + o_ptr->to_h) > 10) {
316         if (one_in_(o_ptr->to_d) || one_in_(o_ptr->to_h)) {
317             break;
318         }
319
320         o_ptr->to_d -= (int)randint0(3);
321         o_ptr->to_h -= (HIT_PROB)randint0(3);
322     }
323 }
324
325 static void reset_flags_poison_needle(ItemEntity *o_ptr)
326 {
327     if (o_ptr->bi_key != BaseitemKey(ItemKindType::SWORD, SV_POISON_NEEDLE)) {
328         return;
329     }
330
331     o_ptr->to_h = 0;
332     o_ptr->to_d = 0;
333     o_ptr->art_flags.reset(TR_BLOWS);
334     o_ptr->art_flags.reset(TR_FORCE_WEAPON);
335     o_ptr->art_flags.reset(TR_SLAY_ANIMAL);
336     o_ptr->art_flags.reset(TR_SLAY_EVIL);
337     o_ptr->art_flags.reset(TR_SLAY_UNDEAD);
338     o_ptr->art_flags.reset(TR_SLAY_DEMON);
339     o_ptr->art_flags.reset(TR_SLAY_ORC);
340     o_ptr->art_flags.reset(TR_SLAY_TROLL);
341     o_ptr->art_flags.reset(TR_SLAY_GIANT);
342     o_ptr->art_flags.reset(TR_SLAY_DRAGON);
343     o_ptr->art_flags.reset(TR_KILL_DRAGON);
344     o_ptr->art_flags.reset(TR_SLAY_HUMAN);
345     o_ptr->art_flags.reset(TR_VORPAL);
346     o_ptr->art_flags.reset(TR_BRAND_POIS);
347     o_ptr->art_flags.reset(TR_BRAND_ACID);
348     o_ptr->art_flags.reset(TR_BRAND_ELEC);
349     o_ptr->art_flags.reset(TR_BRAND_FIRE);
350     o_ptr->art_flags.reset(TR_BRAND_COLD);
351 }
352
353 static int decide_random_art_power_level(ItemEntity *o_ptr, const bool a_cursed, const int total_flags)
354 {
355     if (o_ptr->is_weapon_ammo()) {
356         if (a_cursed) {
357             return 0;
358         }
359
360         if (total_flags < 20000) {
361             return 1;
362         }
363
364         if (total_flags < 45000) {
365             return 2;
366         }
367
368         return 3;
369     }
370
371     if (a_cursed) {
372         return 0;
373     }
374
375     if (total_flags < 15000) {
376         return 1;
377     }
378
379     if (total_flags < 35000) {
380         return 2;
381     }
382
383     return 3;
384 }
385
386 static void name_unnatural_random_artifact(PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll, const int power_level, GAME_TEXT *new_name)
387 {
388     if (!a_scroll) {
389         get_random_name(o_ptr, new_name, o_ptr->is_protector(), power_level);
390         return;
391     }
392
393     GAME_TEXT dummy_name[MAX_NLEN] = "";
394     concptr ask_msg = _("このアーティファクトを何と名付けますか?", "What do you want to call the artifact? ");
395     object_aware(player_ptr, o_ptr);
396     object_known(o_ptr);
397     o_ptr->ident |= IDENT_FULL_KNOWN;
398     o_ptr->art_name = quark_add("");
399     (void)screen_object(player_ptr, o_ptr, 0L);
400     if (!get_string(ask_msg, dummy_name, sizeof dummy_name) || !dummy_name[0]) {
401         if (one_in_(2)) {
402             get_table_sindarin_aux(dummy_name);
403         } else {
404             get_table_name_aux(dummy_name);
405         }
406     }
407
408     sprintf(new_name, _("《%s》", "'%s'"), dummy_name);
409     chg_virtue(player_ptr, V_INDIVIDUALISM, 2);
410     chg_virtue(player_ptr, V_ENCHANT, 5);
411 }
412
413 static void generate_unnatural_random_artifact(
414     PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll, const int power_level, const int max_powers, const int total_flags)
415 {
416     GAME_TEXT new_name[1024];
417     strcpy(new_name, "");
418     name_unnatural_random_artifact(player_ptr, o_ptr, a_scroll, power_level, new_name);
419     o_ptr->art_name = quark_add(new_name);
420     msg_format_wizard(player_ptr, CHEAT_OBJECT,
421         _("パワー %d で 価値%ld のランダムアーティファクト生成 バイアスは「%s」", "Random artifact generated - Power:%d Value:%d Bias:%s."), max_powers,
422         total_flags, artifact_bias_name[o_ptr->artifact_bias]);
423     set_bits(player_ptr->window_flags, PW_INVEN | PW_EQUIP | PW_FLOOR_ITEM_LIST | PW_FOUND_ITEM_LIST);
424 }
425
426 /*!
427  * @brief ランダムアーティファクト生成のメインルーチン
428  * @details 既に生成が済んでいるオブジェクトの構造体を、アーティファクトとして強化する。
429  * @param player_ptr プレイヤーへの参照ポインタ
430  * @param o_ptr 対象のオブジェクト構造体ポインタ
431  * @param a_scroll アーティファクト生成の巻物上の処理。呪いのアーティファクトが生成対象外となる。
432  * @return 常にTRUE(1)を返す
433  */
434 bool become_random_artifact(PlayerType *player_ptr, ItemEntity *o_ptr, bool a_scroll)
435 {
436     o_ptr->artifact_bias = 0;
437     o_ptr->fixed_artifact_idx = FixedArtifactId::NONE;
438     o_ptr->ego_idx = EgoType::NONE;
439     o_ptr->art_flags |= baseitems_info[o_ptr->bi_id].flags;
440
441     bool has_pval = o_ptr->pval != 0;
442     decide_warrior_bias(player_ptr, o_ptr, a_scroll);
443
444     bool a_cursed = decide_random_art_cursed(a_scroll, o_ptr);
445     int powers = decide_random_art_power(a_cursed);
446     int max_powers = powers;
447     invest_powers(player_ptr, o_ptr, &powers, &has_pval, a_cursed);
448     if (has_pval) {
449         strengthen_pval(o_ptr);
450     }
451
452     invest_positive_modified_value(o_ptr);
453     o_ptr->art_flags.set(TR_IGNORE_ACID);
454     o_ptr->art_flags.set(TR_IGNORE_ELEC);
455     o_ptr->art_flags.set(TR_IGNORE_FIRE);
456     o_ptr->art_flags.set(TR_IGNORE_COLD);
457
458     int32_t total_flags = flag_cost(o_ptr, o_ptr->pval);
459     if (a_cursed) {
460         curse_artifact(player_ptr, o_ptr);
461     }
462
463     constexpr auto activation_chance = 3;
464     if (!a_cursed && one_in_(o_ptr->is_protector() ? activation_chance * 2 : activation_chance)) {
465         o_ptr->activation_id = RandomArtActType::NONE;
466         give_activation_power(o_ptr);
467     }
468
469     invest_negative_modified_value(o_ptr);
470     if (((o_ptr->artifact_bias == BIAS_MAGE) || (o_ptr->artifact_bias == BIAS_INT)) && (o_ptr->bi_key.tval() == ItemKindType::GLOVES)) {
471         o_ptr->art_flags.set(TR_FREE_ACT);
472     }
473
474     reset_flags_poison_needle(o_ptr);
475     int power_level = decide_random_art_power_level(o_ptr, a_cursed, total_flags);
476     constexpr auto chance_avoid_weakening = 6;
477     while (has_extreme_damage_rate(player_ptr, o_ptr) && !one_in_(chance_avoid_weakening)) {
478         weakening_artifact(o_ptr);
479     }
480
481     generate_unnatural_random_artifact(player_ptr, o_ptr, a_scroll, power_level, max_powers, total_flags);
482     return true;
483 }