2 * @file random-art-generator.cpp
3 * @brief ランダムアーティファクトの生成メイン定義 / Artifact code
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"
44 static bool weakening_artifact(ItemEntity *o_ptr)
46 const auto bi_id = lookup_baseitem_id({ o_ptr->tval, o_ptr->sval });
47 auto *k_ptr = &baseitems_info[bi_id];
48 auto flgs = object_flags(o_ptr);
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);
56 if (k_ptr->dd < o_ptr->dd) {
61 if (k_ptr->ds < o_ptr->ds) {
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) {
78 static void set_artifact_bias(PlayerType *player_ptr, ItemEntity *o_ptr, int *warrior_artifact_bias)
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;
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;
96 case PlayerClassType::PRIEST:
97 o_ptr->artifact_bias = BIAS_PRIESTLY;
99 case PlayerClassType::ROGUE:
100 case PlayerClassType::NINJA:
101 o_ptr->artifact_bias = BIAS_ROGUE;
102 *warrior_artifact_bias = 25;
104 case PlayerClassType::RANGER:
105 case PlayerClassType::SNIPER:
106 o_ptr->artifact_bias = BIAS_RANGER;
107 *warrior_artifact_bias = 30;
109 case PlayerClassType::PALADIN:
110 o_ptr->artifact_bias = BIAS_PRIESTLY;
111 *warrior_artifact_bias = 40;
113 case PlayerClassType::WARRIOR_MAGE:
114 case PlayerClassType::RED_MAGE:
115 o_ptr->artifact_bias = BIAS_MAGE;
116 *warrior_artifact_bias = 40;
118 case PlayerClassType::CHAOS_WARRIOR:
119 o_ptr->artifact_bias = BIAS_CHAOS;
120 *warrior_artifact_bias = 40;
122 case PlayerClassType::MONK:
123 case PlayerClassType::FORCETRAINER:
124 o_ptr->artifact_bias = BIAS_PRIESTLY;
126 case PlayerClassType::MINDCRAFTER:
127 case PlayerClassType::BARD:
128 if (randint1(5) > 2) {
129 o_ptr->artifact_bias = BIAS_PRIESTLY;
132 case PlayerClassType::TOURIST:
133 if (randint1(5) > 2) {
134 o_ptr->artifact_bias = BIAS_WARRIOR;
137 case PlayerClassType::IMITATOR:
138 if (randint1(2) > 1) {
139 o_ptr->artifact_bias = BIAS_RANGER;
142 case PlayerClassType::BEASTMASTER:
143 o_ptr->artifact_bias = BIAS_CHR;
144 *warrior_artifact_bias = 50;
146 case PlayerClassType::MIRROR_MASTER:
147 if (randint1(4) > 1) {
148 o_ptr->artifact_bias = BIAS_MAGE;
150 o_ptr->artifact_bias = BIAS_ROGUE;
153 case PlayerClassType::ELEMENTALIST:
154 o_ptr->artifact_bias = one_in_(2) ? BIAS_MAGE : BIAS_INT;
157 case PlayerClassType::MAX:
162 static void decide_warrior_bias(PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll)
164 int warrior_artifact_bias = 0;
165 if (a_scroll && one_in_(4)) {
166 set_artifact_bias(player_ptr, o_ptr, &warrior_artifact_bias);
169 if (a_scroll && (randint1(100) <= warrior_artifact_bias)) {
170 o_ptr->artifact_bias = BIAS_WARRIOR;
174 static bool decide_random_art_cursed(const bool a_scroll, ItemEntity *o_ptr)
176 constexpr auto chance_cursed = 13;
177 if (!a_scroll && one_in_(chance_cursed)) {
181 if (((o_ptr->tval == ItemKindType::AMULET) || (o_ptr->tval == ItemKindType::RING)) && o_ptr->is_cursed()) {
188 static int decide_random_art_power(const bool a_cursed)
190 int powers = randint1(5) + 1;
191 while (one_in_(powers) || one_in_(7) || one_in_(10)) {
195 if (!a_cursed && one_in_(CHANCE_STRENGTHENING)) {
206 static void invest_powers(PlayerType *player_ptr, ItemEntity *o_ptr, int *powers, bool *has_pval, const bool a_cursed)
208 int max_type = o_ptr->is_weapon_ammo() ? 7 : 5;
209 while ((*powers)--) {
210 switch (randint1(max_type)) {
218 if (one_in_(2) && o_ptr->is_weapon_ammo() && (o_ptr->tval != ItemKindType::BOW)) {
219 if (a_cursed && !one_in_(13)) {
223 if (one_in_(o_ptr->ds + 4)) {
227 if (one_in_(o_ptr->dd + 1)) {
232 random_resistance(o_ptr);
237 random_misc(player_ptr, o_ptr);
245 msg_print("Switch error in become_random_artifact!");
253 static void strengthen_pval(ItemEntity *o_ptr)
255 if (o_ptr->art_flags.has(TR_BLOWS)) {
256 o_ptr->pval = randint1(2);
257 if ((o_ptr->tval == ItemKindType::SWORD) && (o_ptr->sval == SV_HAYABUSA)) {
263 } while (o_ptr->pval < randint1(5) || one_in_(o_ptr->pval));
266 if ((o_ptr->pval > 4) && !one_in_(CHANCE_STRENGTHENING)) {
272 * @brief 防具ならばAC修正、武具なら殺戮修正を付与する
273 * @param player_ptr プレイヤーへの参照ポインタ
274 * @param o_ptr ランダムアーティファクトを示すアイテムへの参照ポインタ
276 static void invest_positive_modified_value(ItemEntity *o_ptr)
278 if (o_ptr->is_armour()) {
279 o_ptr->to_a += randint1(o_ptr->to_a > 19 ? 1 : 20 - o_ptr->to_a);
283 if (!o_ptr->is_weapon_ammo()) {
287 o_ptr->to_h += randint1(o_ptr->to_h > 19 ? 1 : 20 - o_ptr->to_h);
288 o_ptr->to_d += randint1(o_ptr->to_d > 19 ? 1 : 20 - o_ptr->to_d);
289 if ((o_ptr->art_flags.has(TR_WIS)) && (o_ptr->pval > 0)) {
290 o_ptr->art_flags.set(TR_BLESSED);
295 * @brief 防具のAC修正が高すぎた場合に弱化させる
296 * @param player_ptr プレイヤーへの参照ポインタ
297 * @param o_ptr ランダムアーティファクトを示すアイテムへの参照ポインタ
299 static void invest_negative_modified_value(ItemEntity *o_ptr)
301 if (!o_ptr->is_armour()) {
305 while ((o_ptr->to_d + o_ptr->to_h) > 20) {
306 if (one_in_(o_ptr->to_d) && one_in_(o_ptr->to_h)) {
310 o_ptr->to_d -= (int)randint0(3);
311 o_ptr->to_h -= (HIT_PROB)randint0(3);
314 while ((o_ptr->to_d + o_ptr->to_h) > 10) {
315 if (one_in_(o_ptr->to_d) || one_in_(o_ptr->to_h)) {
319 o_ptr->to_d -= (int)randint0(3);
320 o_ptr->to_h -= (HIT_PROB)randint0(3);
324 static void reset_flags_poison_needle(ItemEntity *o_ptr)
326 if ((o_ptr->tval != ItemKindType::SWORD) || (o_ptr->sval != SV_POISON_NEEDLE)) {
332 o_ptr->art_flags.reset(TR_BLOWS);
333 o_ptr->art_flags.reset(TR_FORCE_WEAPON);
334 o_ptr->art_flags.reset(TR_SLAY_ANIMAL);
335 o_ptr->art_flags.reset(TR_SLAY_EVIL);
336 o_ptr->art_flags.reset(TR_SLAY_UNDEAD);
337 o_ptr->art_flags.reset(TR_SLAY_DEMON);
338 o_ptr->art_flags.reset(TR_SLAY_ORC);
339 o_ptr->art_flags.reset(TR_SLAY_TROLL);
340 o_ptr->art_flags.reset(TR_SLAY_GIANT);
341 o_ptr->art_flags.reset(TR_SLAY_DRAGON);
342 o_ptr->art_flags.reset(TR_KILL_DRAGON);
343 o_ptr->art_flags.reset(TR_SLAY_HUMAN);
344 o_ptr->art_flags.reset(TR_VORPAL);
345 o_ptr->art_flags.reset(TR_BRAND_POIS);
346 o_ptr->art_flags.reset(TR_BRAND_ACID);
347 o_ptr->art_flags.reset(TR_BRAND_ELEC);
348 o_ptr->art_flags.reset(TR_BRAND_FIRE);
349 o_ptr->art_flags.reset(TR_BRAND_COLD);
352 static int decide_random_art_power_level(ItemEntity *o_ptr, const bool a_cursed, const int total_flags)
354 if (o_ptr->is_weapon_ammo()) {
359 if (total_flags < 20000) {
363 if (total_flags < 45000) {
374 if (total_flags < 15000) {
378 if (total_flags < 35000) {
385 static void name_unnatural_random_artifact(PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll, const int power_level, GAME_TEXT *new_name)
388 get_random_name(o_ptr, new_name, o_ptr->is_armour(), power_level);
392 GAME_TEXT dummy_name[MAX_NLEN] = "";
393 concptr ask_msg = _("このアーティファクトを何と名付けますか?", "What do you want to call the artifact? ");
394 object_aware(player_ptr, o_ptr);
396 o_ptr->ident |= IDENT_FULL_KNOWN;
397 o_ptr->art_name = quark_add("");
398 (void)screen_object(player_ptr, o_ptr, 0L);
399 if (!get_string(ask_msg, dummy_name, sizeof dummy_name) || !dummy_name[0]) {
401 get_table_sindarin_aux(dummy_name);
403 get_table_name_aux(dummy_name);
407 sprintf(new_name, _("《%s》", "'%s'"), dummy_name);
408 chg_virtue(player_ptr, V_INDIVIDUALISM, 2);
409 chg_virtue(player_ptr, V_ENCHANT, 5);
412 static void generate_unnatural_random_artifact(
413 PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll, const int power_level, const int max_powers, const int total_flags)
415 GAME_TEXT new_name[1024];
416 strcpy(new_name, "");
417 name_unnatural_random_artifact(player_ptr, o_ptr, a_scroll, power_level, new_name);
418 o_ptr->art_name = quark_add(new_name);
419 msg_format_wizard(player_ptr, CHEAT_OBJECT,
420 _("パワー %d で 価値%ld のランダムアーティファクト生成 バイアスは「%s」", "Random artifact generated - Power:%d Value:%d Bias:%s."), max_powers,
421 total_flags, artifact_bias_name[o_ptr->artifact_bias]);
422 set_bits(player_ptr->window_flags, PW_INVEN | PW_EQUIP | PW_FLOOR_ITEM_LIST);
426 * @brief ランダムアーティファクト生成のメインルーチン
427 * @details 既に生成が済んでいるオブジェクトの構造体を、アーティファクトとして強化する。
428 * @param player_ptr プレイヤーへの参照ポインタ
429 * @param o_ptr 対象のオブジェクト構造体ポインタ
430 * @param a_scroll アーティファクト生成の巻物上の処理。呪いのアーティファクトが生成対象外となる。
431 * @return 常にTRUE(1)を返す
433 bool become_random_artifact(PlayerType *player_ptr, ItemEntity *o_ptr, bool a_scroll)
435 o_ptr->artifact_bias = 0;
436 o_ptr->fixed_artifact_idx = FixedArtifactId::NONE;
437 o_ptr->ego_idx = EgoType::NONE;
438 o_ptr->art_flags |= baseitems_info[o_ptr->bi_id].flags;
440 bool has_pval = o_ptr->pval != 0;
441 decide_warrior_bias(player_ptr, o_ptr, a_scroll);
443 bool a_cursed = decide_random_art_cursed(a_scroll, o_ptr);
444 int powers = decide_random_art_power(a_cursed);
445 int max_powers = powers;
446 invest_powers(player_ptr, o_ptr, &powers, &has_pval, a_cursed);
448 strengthen_pval(o_ptr);
451 invest_positive_modified_value(o_ptr);
452 o_ptr->art_flags.set(TR_IGNORE_ACID);
453 o_ptr->art_flags.set(TR_IGNORE_ELEC);
454 o_ptr->art_flags.set(TR_IGNORE_FIRE);
455 o_ptr->art_flags.set(TR_IGNORE_COLD);
457 int32_t total_flags = flag_cost(o_ptr, o_ptr->pval);
459 curse_artifact(player_ptr, o_ptr);
462 constexpr auto activation_chance = 3;
463 if (!a_cursed && one_in_(o_ptr->is_armour() ? activation_chance * 2 : activation_chance)) {
464 o_ptr->activation_id = RandomArtActType::NONE;
465 give_activation_power(o_ptr);
468 invest_negative_modified_value(o_ptr);
469 if (((o_ptr->artifact_bias == BIAS_MAGE) || (o_ptr->artifact_bias == BIAS_INT)) && (o_ptr->tval == ItemKindType::GLOVES)) {
470 o_ptr->art_flags.set(TR_FREE_ACT);
473 reset_flags_poison_needle(o_ptr);
474 int power_level = decide_random_art_power_level(o_ptr, a_cursed, total_flags);
475 constexpr auto chance_avoid_weakening = 6;
476 while (has_extreme_damage_rate(player_ptr, o_ptr) && !one_in_(chance_avoid_weakening)) {
477 weakening_artifact(o_ptr);
480 generate_unnatural_random_artifact(player_ptr, o_ptr, a_scroll, power_level, max_powers, total_flags);