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 "object/object-kind.h"
25 #include "player/player-sex.h"
26 #include "specific-object/bloody-moon.h"
27 #include "system/artifact-type-definition.h"
28 #include "system/floor-type-definition.h"
29 #include "system/object-type-definition.h"
30 #include "system/player-type-definition.h"
31 #include "util/bit-flags-calculator.h"
35 * @param player_ptr プレイヤーへの参照ポインタ
36 * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
37 * @return 追加能力/耐性がもらえるならtrue、もらえないならfalse
39 * 純戦士系職業は追加能力/耐性がもらえる。
40 * それ以外では、反感、太古の怨念、呪いが付き追加能力/耐性はもらえない。
42 static bool invest_terror_mask(player_type *player_ptr, object_type *o_ptr)
44 if (o_ptr->name1 != ART_TERROR)
47 switch (player_ptr->pclass) {
54 o_ptr->art_flags.set(TR_AGGRAVATE);
55 o_ptr->art_flags.set(TR_TY_CURSE);
56 o_ptr->curse_flags.set({ TRC::CURSED, TRC::HEAVY_CURSE });
57 o_ptr->curse_flags.set(get_curse(2, o_ptr));
63 * @brief 戦乙女ミリムの危ない水着への特殊処理 (セクシーギャルのみpval追加)
64 * @param player_ptr プレイヤーへの参照ポインタ
65 * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
67 static void milim_swimsuit(player_type *player_ptr, object_type *o_ptr)
69 if ((o_ptr->name1 != ART_MILIM) || (player_ptr->ppersonality != PERSONALITY_SEXY))
73 o_ptr->art_flags.set(TR_STR);
74 o_ptr->art_flags.set(TR_INT);
75 o_ptr->art_flags.set(TR_WIS);
76 o_ptr->art_flags.set(TR_DEX);
77 o_ptr->art_flags.set(TR_CON);
78 o_ptr->art_flags.set(TR_CHR);
82 * @brief 特定の固定アーティファクトの条件付き追加能力/耐性を付加する
83 * @attention プレイヤーの各種ステータスに依存した処理がある。
84 * @todo 折を見て関数名を変更すること。
85 * @param player_ptr プレイヤーへの参照ポインタ
86 * @param o_ptr 対象のオブジェクト構造体ポインタ
87 * @param a_ptr 生成する固定アーティファクト構造体ポインタ
89 * 対象は村正、ロビントンのハープ、龍争虎鬪、ブラッディムーン、羽衣、天女の羽衣、ミリム
91 static void invest_special_artifact_abilities(player_type *player_ptr, object_type *o_ptr)
93 switch (o_ptr->name1) {
95 if (player_ptr->pclass != CLASS_SAMURAI) {
96 o_ptr->art_flags.set(TR_NO_MAGIC);
97 o_ptr->curse_flags.set(TRC::HEAVY_CURSE);
101 if (player_ptr->pclass == CLASS_BARD)
102 o_ptr->art_flags.set(TR_DEC_MANA);
105 if (player_ptr->pclass == CLASS_MONK)
106 o_ptr->art_flags.set(TR_BLOWS);
109 get_bloody_moon_flags(o_ptr);
111 case ART_HEAVENLY_MAIDEN:
112 if (player_ptr->psex != SEX_FEMALE)
113 o_ptr->art_flags.set(TR_AGGRAVATE);
116 milim_swimsuit(player_ptr, o_ptr);
124 * @brief 固定アーティファクトオブジェクトに追加能力/耐性を付加する
125 * @param player_ptr プレイヤー情報への参照ポインタ
126 * @param a_ptr 固定アーティファクト情報への参照ポインタ
127 * @param q_ptr オブジェクト情報への参照ポインタ
129 static void fixed_artifact_random_abilities(player_type *player_ptr, artifact_type *a_ptr, object_type *o_ptr)
131 auto give_power = false;
132 auto give_resistance = false;
134 if (invest_terror_mask(player_ptr, o_ptr)) {
136 give_resistance = true;
139 invest_special_artifact_abilities(player_ptr, o_ptr);
141 if (a_ptr->gen_flags.has(TRG::XTRA_POWER))
144 if (a_ptr->gen_flags.has(TRG::XTRA_H_RES))
145 give_resistance = true;
147 if (a_ptr->gen_flags.has(TRG::XTRA_RES_OR_POWER)) {
149 give_resistance = true;
158 one_high_resistance(o_ptr);
160 if (a_ptr->gen_flags.has(TRG::XTRA_DICE)) {
163 } while (one_in_(o_ptr->dd));
171 * @brief 固定アーティファクトオブジェクトに呪いフラグを付加する
172 * @param player_ptr プレイヤー情報への参照ポインタ
173 * @param a_ptr 固定アーティファクト情報への参照ポインタ
174 * @param q_ptr オブジェクト情報への参照ポインタ
176 static void invest_curse_to_fixed_artifact(artifact_type *a_ptr, object_type *o_ptr)
179 set_bits(o_ptr->ident, IDENT_BROKEN);
181 if (a_ptr->gen_flags.has(TRG::CURSED))
182 o_ptr->curse_flags.set(TRC::CURSED);
184 if (a_ptr->gen_flags.has(TRG::HEAVY_CURSE))
185 o_ptr->curse_flags.set(TRC::HEAVY_CURSE);
187 if (a_ptr->gen_flags.has(TRG::PERMA_CURSE))
188 o_ptr->curse_flags.set(TRC::PERMA_CURSE);
190 if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE0))
191 o_ptr->curse_flags.set(get_curse(0, o_ptr));
193 if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE1))
194 o_ptr->curse_flags.set(get_curse(1, o_ptr));
196 if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE2))
197 o_ptr->curse_flags.set(get_curse(2, o_ptr));
201 * @brief オブジェクトに指定した固定アーティファクトをオブジェクトに割り当てる。
202 * @param player_ptr プレイヤーへの参照ポインタ
203 * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
204 * @return 適用したアーティファクト情報への参照ポインタ
206 artifact_type *apply_artifact(player_type *player_ptr, object_type *o_ptr)
208 auto a_ptr = &a_info[o_ptr->name1];
209 o_ptr->pval = a_ptr->pval;
210 o_ptr->ac = a_ptr->ac;
211 o_ptr->dd = a_ptr->dd;
212 o_ptr->ds = a_ptr->ds;
213 o_ptr->to_a = a_ptr->to_a;
214 o_ptr->to_h = a_ptr->to_h;
215 o_ptr->to_d = a_ptr->to_d;
216 o_ptr->weight = a_ptr->weight;
217 o_ptr->xtra2 = a_ptr->act_idx;
219 invest_curse_to_fixed_artifact(a_ptr, o_ptr);
220 fixed_artifact_random_abilities(player_ptr, a_ptr, o_ptr);
226 * @brief フロアの指定された位置に固定アーティファクトを生成する。 / Create the artifact of the specified number
227 * @details 固定アーティファクト構造体から基本ステータスをコピーした後、所定の座標でdrop_item()で落とす。
228 * @param player_ptr プレイヤーへの参照ポインタ
229 * @param a_idx 生成する固定アーティファクト構造体のID
230 * @param y アイテムを落とす地点のy座標
231 * @param x アイテムを落とす地点のx座標
232 * @return 生成が成功したか否か、失敗はIDの不全、ベースアイテムの不全、drop_item()の失敗時に起こる。
233 * @attention この処理はdrop_near()内で普通の固定アーティファクトが重ならない性質に依存する.
234 * 仮に2個以上存在可能かつ装備品以外の固定アーティファクトが作成されれば
235 * drop_near()関数の返り値は信用できなくなる.
237 bool create_named_art(player_type *player_ptr, ARTIFACT_IDX a_idx, POSITION y, POSITION x)
239 auto a_ptr = &a_info[a_idx];
240 if (a_ptr->name.empty())
243 auto i = lookup_kind(a_ptr->tval, a_ptr->sval);
250 q_ptr->name1 = a_idx;
252 (void)apply_artifact(player_ptr, q_ptr);
254 return drop_near(player_ptr, q_ptr, -1, y, x) ? true : false;
258 * @brief 非INSTA_ART型の固定アーティファクトの生成を確率に応じて試行する。
259 * Mega-Hack -- Attempt to create one of the "Special Objects"
260 * @param player_ptr プレイヤーへの参照ポインタ
261 * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
262 * @return 生成に成功したらTRUEを返す。
264 * Attempt to change an object into an artifact\n
265 * This routine should only be called by "apply_magic()"\n
266 * Note -- see "make_artifact_special()" and "apply_magic()"\n
268 bool make_artifact(player_type *player_ptr, object_type *o_ptr)
270 auto floor_ptr = player_ptr->current_floor_ptr;
271 if (floor_ptr->dun_level == 0)
274 if (o_ptr->number != 1)
277 for (const auto &a_ref : a_info) {
278 if (a_ref.name.empty())
284 if (a_ref.gen_flags.has(TRG::QUESTITEM))
287 if (a_ref.gen_flags.has(TRG::INSTA_ART))
290 if (a_ref.tval != o_ptr->tval)
293 if (a_ref.sval != o_ptr->sval)
296 if (a_ref.level > floor_ptr->dun_level) {
297 int d = (a_ref.level - floor_ptr->dun_level) * 2;
302 if (!one_in_(a_ref.rarity))
305 o_ptr->name1 = a_ref.idx;
313 * @brief INSTA_ART型の固定アーティファクトの生成を確率に応じて試行する。
314 * Mega-Hack -- Attempt to create one of the "Special Objects"
315 * @param player_ptr プレイヤーへの参照ポインタ
316 * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
317 * @return 生成に成功したらTRUEを返す。
319 * We are only called from "make_object()", and we assume that\n
320 * "apply_magic()" is called immediately after we return.\n
322 * Note -- see "make_artifact()" and "apply_magic()"\n
324 bool make_artifact_special(player_type *player_ptr, object_type *o_ptr)
326 KIND_OBJECT_IDX k_idx = 0;
328 /*! @note 地上ではキャンセルする / No artifacts in the town */
329 auto floor_ptr = player_ptr->current_floor_ptr;
330 if (floor_ptr->dun_level == 0)
333 /*! @note get_obj_num_hookによる指定がある場合は生成をキャンセルする / Themed object */
334 if (get_obj_num_hook)
337 /*! @note 全固定アーティファクト中からIDの若い順に生成対象とその確率を走査する / Check the artifact list (just the "specials") */
338 for (const auto &a_ref : a_info) {
339 /*! @note アーティファクト名が空の不正なデータは除外する / Skip "empty" artifacts */
340 if (a_ref.name.empty())
343 /*! @note 既に生成回数がカウントされたアーティファクト、QUESTITEMと非INSTA_ARTは除外 / Cannot make an artifact twice */
346 if (a_ref.gen_flags.has(TRG::QUESTITEM))
348 if (!(a_ref.gen_flags.has(TRG::INSTA_ART)))
351 /*! @note アーティファクト生成階が現在に対して足りない場合は高確率で1/(不足階層*2)を満たさないと生成リストに加えられない /
352 * XXX XXX Enforce minimum "depth" (loosely) */
353 if (a_ref.level > floor_ptr->object_level) {
354 /* @note / Acquire the "out-of-depth factor". Roll for out-of-depth creation. */
355 int d = (a_ref.level - floor_ptr->object_level) * 2;
360 /*! @note 1/(レア度)の確率を満たさないと除外される / Artifact "rarity roll" */
361 if (!one_in_(a_ref.rarity))
364 /*! @note INSTA_ART型固定アーティファクトのベースアイテムもチェック対象とする。ベースアイテムの生成階層が足りない場合1/(不足階層*5)
365 * を満たさないと除外される。 / Find the base object. XXX XXX Enforce minimum "object" level (loosely). Acquire the "out-of-depth factor". Roll for
366 * out-of-depth creation. */
367 k_idx = lookup_kind(a_ref.tval, a_ref.sval);
368 if (k_info[k_idx].level > floor_ptr->object_level) {
369 int d = (k_info[k_idx].level - floor_ptr->object_level) * 5;
374 /*! @note 前述の条件を満たしたら、後のIDのアーティファクトはチェックせずすぐ確定し生成処理に移す /
375 * Assign the template. Mega-Hack -- mark the item as an artifact. Hack: Some artifacts get random extra powers. Success. */
378 o_ptr->name1 = a_ref.idx;
382 /*! @note 全INSTA_ART固定アーティファクトを試行しても決まらなかった場合 FALSEを返す / Failure */