2 * @file fixed-art-generator.cpp
3 * @brief 固定アーティファクトの生成 / Artifact code
6 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
7 * This software may be copied and distributed for educational, research, and
8 * not for profit purposes provided that this copyright and statement are
9 * included in all such copies.
10 * 2013 Deskull rearranged comment for Doxygen.
11 * 2020 Hourier rearranged
14 #include "artifact/fixed-art-generator.h"
15 #include "artifact/fixed-art-types.h"
16 #include "floor/floor-object.h"
17 #include "object-enchant/object-boost.h"
18 #include "object-enchant/object-curse.h"
19 #include "object-enchant/special-object-flags.h"
20 #include "object-enchant/tr-types.h"
21 #include "object-enchant/trc-types.h"
22 #include "object-enchant/trg-types.h"
23 #include "object/object-kind-hook.h"
24 #include "player-base/player-class.h"
25 #include "player/player-sex.h"
26 #include "specific-object/bloody-moon.h"
27 #include "system/artifact-type-definition.h"
28 #include "system/baseitem-info.h"
29 #include "system/floor-type-definition.h"
30 #include "system/item-entity.h"
31 #include "system/player-type-definition.h"
32 #include "util/bit-flags-calculator.h"
36 * @param player_ptr プレイヤーへの参照ポインタ
37 * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
38 * @return 追加能力/耐性がもらえるならtrue、もらえないならfalse
40 * 純戦士系職業は追加能力/耐性がもらえる。
41 * それ以外では、反感、太古の怨念、呪いが付き追加能力/耐性はもらえない。
43 static bool invest_terror_mask(PlayerType *player_ptr, ItemEntity *o_ptr)
45 if (!o_ptr->is_specific_artifact(FixedArtifactId::TERROR)) {
49 switch (player_ptr->pclass) {
50 case PlayerClassType::WARRIOR:
51 case PlayerClassType::ARCHER:
52 case PlayerClassType::CAVALRY:
53 case PlayerClassType::BERSERKER:
56 o_ptr->art_flags.set(TR_AGGRAVATE);
57 o_ptr->art_flags.set(TR_TY_CURSE);
58 o_ptr->curse_flags.set({ CurseTraitType::CURSED, CurseTraitType::HEAVY_CURSE });
59 o_ptr->curse_flags.set(get_curse(2, o_ptr));
65 * @brief 戦乙女ミリムの危ない水着への特殊処理 (セクシーギャルのみpval追加)
66 * @param player_ptr プレイヤーへの参照ポインタ
67 * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
69 static void milim_swimsuit(PlayerType *player_ptr, ItemEntity *o_ptr)
71 if (!o_ptr->is_specific_artifact(FixedArtifactId::MILIM) || (player_ptr->ppersonality != PERSONALITY_SEXY)) {
76 o_ptr->art_flags.set(TR_STR);
77 o_ptr->art_flags.set(TR_INT);
78 o_ptr->art_flags.set(TR_WIS);
79 o_ptr->art_flags.set(TR_DEX);
80 o_ptr->art_flags.set(TR_CON);
81 o_ptr->art_flags.set(TR_CHR);
85 * @brief 特定の固定アーティファクトの条件付き追加能力/耐性を付加する
86 * @attention プレイヤーの各種ステータスに依存した処理がある。
87 * @todo 折を見て関数名を変更すること。
88 * @param player_ptr プレイヤーへの参照ポインタ
89 * @param o_ptr 対象のオブジェクト構造体ポインタ
90 * @param a_ptr 生成する固定アーティファクト構造体ポインタ
92 * 対象は村正、ロビントンのハープ、龍争虎鬪、ブラッディムーン、羽衣、天女の羽衣、ミリム
94 static void invest_special_artifact_abilities(PlayerType *player_ptr, ItemEntity *o_ptr)
96 const auto pc = PlayerClass(player_ptr);
97 switch (o_ptr->fixed_artifact_idx) {
98 case FixedArtifactId::MURAMASA:
99 if (!pc.equals(PlayerClassType::SAMURAI)) {
100 o_ptr->art_flags.set(TR_NO_MAGIC);
101 o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
104 case FixedArtifactId::ROBINTON:
105 if (pc.equals(PlayerClassType::BARD)) {
106 o_ptr->art_flags.set(TR_DEC_MANA);
109 case FixedArtifactId::XIAOLONG:
110 if (pc.equals(PlayerClassType::MONK)) {
111 o_ptr->art_flags.set(TR_BLOWS);
114 case FixedArtifactId::BLOOD:
115 get_bloody_moon_flags(o_ptr);
117 case FixedArtifactId::HEAVENLY_MAIDEN:
118 if (player_ptr->psex != SEX_FEMALE) {
119 o_ptr->art_flags.set(TR_AGGRAVATE);
122 case FixedArtifactId::MILIM:
123 milim_swimsuit(player_ptr, o_ptr);
131 * @brief 固定アーティファクトオブジェクトに追加能力/耐性を付加する
132 * @param player_ptr プレイヤー情報への参照ポインタ
133 * @param a_ptr 固定アーティファクト情報への参照ポインタ
134 * @param q_ptr オブジェクト情報への参照ポインタ
136 static void fixed_artifact_random_abilities(PlayerType *player_ptr, const ArtifactType &a_ref, ItemEntity *o_ptr)
138 auto give_power = false;
139 auto give_resistance = false;
141 if (invest_terror_mask(player_ptr, o_ptr)) {
143 give_resistance = true;
146 invest_special_artifact_abilities(player_ptr, o_ptr);
148 if (a_ref.gen_flags.has(ItemGenerationTraitType::XTRA_POWER)) {
152 if (a_ref.gen_flags.has(ItemGenerationTraitType::XTRA_H_RES)) {
153 give_resistance = true;
156 if (a_ref.gen_flags.has(ItemGenerationTraitType::XTRA_RES_OR_POWER)) {
158 give_resistance = true;
168 if (give_resistance) {
169 one_high_resistance(o_ptr);
172 if (a_ref.gen_flags.has(ItemGenerationTraitType::XTRA_DICE)) {
175 } while (one_in_(o_ptr->dd));
184 * @brief 固定アーティファクトオブジェクトに呪いフラグを付加する
185 * @param player_ptr プレイヤー情報への参照ポインタ
186 * @param a_ptr 固定アーティファクト情報への参照ポインタ
187 * @param q_ptr オブジェクト情報への参照ポインタ
189 static void invest_curse_to_fixed_artifact(const ArtifactType &a_ref, ItemEntity *o_ptr)
192 set_bits(o_ptr->ident, IDENT_BROKEN);
195 if (a_ref.gen_flags.has(ItemGenerationTraitType::CURSED)) {
196 o_ptr->curse_flags.set(CurseTraitType::CURSED);
199 if (a_ref.gen_flags.has(ItemGenerationTraitType::HEAVY_CURSE)) {
200 o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
203 if (a_ref.gen_flags.has(ItemGenerationTraitType::PERMA_CURSE)) {
204 o_ptr->curse_flags.set(CurseTraitType::PERMA_CURSE);
207 if (a_ref.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE0)) {
208 o_ptr->curse_flags.set(get_curse(0, o_ptr));
211 if (a_ref.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE1)) {
212 o_ptr->curse_flags.set(get_curse(1, o_ptr));
215 if (a_ref.gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE2)) {
216 o_ptr->curse_flags.set(get_curse(2, o_ptr));
221 * @brief オブジェクトに指定した固定アーティファクトをオブジェクトに割り当てる。
222 * @param player_ptr プレイヤーへの参照ポインタ
223 * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
224 * @return 適用したアーティファクト情報への参照ポインタ
226 void apply_artifact(PlayerType *player_ptr, ItemEntity *o_ptr)
228 auto &a_ref = artifacts_info.at(o_ptr->fixed_artifact_idx);
229 o_ptr->pval = a_ref.pval;
230 o_ptr->ac = a_ref.ac;
231 o_ptr->dd = a_ref.dd;
232 o_ptr->ds = a_ref.ds;
233 o_ptr->to_a = a_ref.to_a;
234 o_ptr->to_h = a_ref.to_h;
235 o_ptr->to_d = a_ref.to_d;
236 o_ptr->weight = a_ref.weight;
237 o_ptr->activation_id = a_ref.act_idx;
239 invest_curse_to_fixed_artifact(a_ref, o_ptr);
240 fixed_artifact_random_abilities(player_ptr, a_ref, o_ptr);
244 * @brief フロアの指定された位置に固定アーティファクトを生成する。 / Create the artifact of the specified number
245 * @details 固定アーティファクト構造体から基本ステータスをコピーした後、所定の座標でdrop_item()で落とす。
246 * @param player_ptr プレイヤーへの参照ポインタ
247 * @param a_idx 生成する固定アーティファクト構造体のID
248 * @param y アイテムを落とす地点のy座標
249 * @param x アイテムを落とす地点のx座標
250 * @return 生成が成功したか否か、失敗はIDの不全、ベースアイテムの不全、drop_item()の失敗時に起こる。
251 * @attention この処理はdrop_near()内で普通の固定アーティファクトが重ならない性質に依存する.
252 * 仮に2個以上存在可能かつ装備品以外の固定アーティファクトが作成されれば
253 * drop_near()関数の返り値は信用できなくなる.
255 bool create_named_art(PlayerType *player_ptr, FixedArtifactId a_idx, POSITION y, POSITION x)
257 auto &a_ref = artifacts_info.at(a_idx);
258 if (a_ref.name.empty()) {
262 auto bi_id = lookup_baseitem_id(a_ref.bi_key);
270 q_ptr->fixed_artifact_idx = a_idx;
271 apply_artifact(player_ptr, q_ptr);
272 if (drop_near(player_ptr, q_ptr, -1, y, x) == 0) {
276 a_ref.is_generated = true;
281 * @brief 非INSTA_ART型の固定アーティファクトの生成を確率に応じて試行する。
282 * Mega-Hack -- Attempt to create one of the "Special Objects"
283 * @param player_ptr プレイヤーへの参照ポインタ
284 * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
285 * @return 生成に成功したらTRUEを返す。
287 * Attempt to change an object into an artifact\n
288 * This routine should only be called by "apply_magic()"\n
289 * Note -- see "make_artifact_special()" and "apply_magic()"\n
291 bool make_artifact(PlayerType *player_ptr, ItemEntity *o_ptr)
293 auto floor_ptr = player_ptr->current_floor_ptr;
294 if (floor_ptr->dun_level == 0) {
298 if (o_ptr->number != 1) {
302 for (const auto &[a_idx, a_ref] : artifacts_info) {
303 if (a_ref.name.empty()) {
307 if (a_ref.is_generated) {
311 if (a_ref.gen_flags.has(ItemGenerationTraitType::QUESTITEM)) {
315 if (a_ref.gen_flags.has(ItemGenerationTraitType::INSTA_ART)) {
319 if (a_ref.bi_key != o_ptr->bi_key) {
323 if (a_ref.level > floor_ptr->dun_level) {
324 int d = (a_ref.level - floor_ptr->dun_level) * 2;
330 if (!one_in_(a_ref.rarity)) {
334 o_ptr->fixed_artifact_idx = a_idx;
342 * @brief INSTA_ART型の固定アーティファクトの生成を確率に応じて試行する。
343 * Mega-Hack -- Attempt to create one of the "Special Objects"
344 * @param player_ptr プレイヤーへの参照ポインタ
345 * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
346 * @return 生成に成功したらTRUEを返す。
348 * We are only called from "make_object()", and we assume that\n
349 * "apply_magic()" is called immediately after we return.\n
351 * Note -- see "make_artifact()" and "apply_magic()"\n
353 bool make_artifact_special(PlayerType *player_ptr, ItemEntity *o_ptr)
355 /*! @note 地上ではキャンセルする / No artifacts in the town */
356 auto floor_ptr = player_ptr->current_floor_ptr;
357 if (floor_ptr->dun_level == 0) {
361 /*! @note get_obj_index_hookによる指定がある場合は生成をキャンセルする / Themed object */
362 if (get_obj_index_hook) {
366 /*! @note 全固定アーティファクト中からIDの若い順に生成対象とその確率を走査する / Check the artifact list (just the "specials") */
367 for (const auto &[a_idx, a_ref] : artifacts_info) {
368 /*! @note アーティファクト名が空の不正なデータは除外する / Skip "empty" artifacts */
369 if (a_ref.name.empty()) {
373 /*! @note 既に生成回数がカウントされたアーティファクト、QUESTITEMと非INSTA_ARTは除外 / Cannot make an artifact twice */
374 if (a_ref.is_generated) {
377 if (a_ref.gen_flags.has(ItemGenerationTraitType::QUESTITEM)) {
380 if (!(a_ref.gen_flags.has(ItemGenerationTraitType::INSTA_ART))) {
384 /*! @note アーティファクト生成階が現在に対して足りない場合は高確率で1/(不足階層*2)を満たさないと生成リストに加えられない */
385 if (a_ref.level > floor_ptr->object_level) {
386 /* @note / Acquire the "out-of-depth factor". Roll for out-of-depth creation. */
387 int d = (a_ref.level - floor_ptr->object_level) * 2;
393 /*! @note 1/(レア度)の確率を満たさないと除外される / Artifact "rarity roll" */
394 if (!one_in_(a_ref.rarity)) {
399 * @note INSTA_ART型固定アーティファクトのベースアイテムもチェック対象とする。
400 * ベースアイテムの生成階層が足りない場合1/(不足階層*5)を満たさないと除外される。
402 const auto bi_id = lookup_baseitem_id(a_ref.bi_key);
403 if (baseitems_info[bi_id].level > floor_ptr->object_level) {
404 int d = (baseitems_info[bi_id].level - floor_ptr->object_level) * 5;
410 /*! @note 前述の条件を満たしたら、後のIDのアーティファクトはチェックせずすぐ確定し生成処理に移す /
411 * Assign the template. Mega-Hack -- mark the item as an artifact. Hack: Some artifacts get random extra powers. Success. */
414 o_ptr->fixed_artifact_idx = a_idx;
418 /*! @note 全INSTA_ART固定アーティファクトを試行しても決まらなかった場合 FALSEを返す / Failure */