OSDN Git Service

Merge pull request #493 from habu1010/feature/fix-FlagGroup-constant-definition-for...
[hengbandforosx/hengbandosx.git] / src / artifact / fixed-art-generator.cpp
1 /*!
2  * @brief 固定アーティファクトの生成 / Artifact code
3  * @date 2020/07/14
4  * @author
5  * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
6  * This software may be copied and distributed for educational, research, and
7  * not for profit purposes provided that this copyright and statement are
8  * included in all such copies.
9  * 2013 Deskull rearranged comment for Doxygen.
10  * 2020 Hourier rearranged
11  */
12
13 #include "artifact/fixed-art-generator.h"
14 #include "artifact/fixed-art-types.h"
15 #include "floor/floor-object.h"
16 #include "object-enchant/object-boost.h"
17 #include "object-enchant/object-curse.h"
18 #include "object-enchant/tr-types.h"
19 #include "object-enchant/trc-types.h"
20 #include "object-enchant/trg-types.h"
21 #include "object/object-generator.h"
22 #include "object/object-kind-hook.h"
23 #include "object/object-kind.h"
24 #include "specific-object/bloody-moon.h"
25 #include "system/artifact-type-definition.h"
26 #include "system/floor-type-definition.h"
27 #include "system/system-variables.h"
28 #include "util/bit-flags-calculator.h"
29
30 /*!
31  * @brief 恐怖の仮面への特殊処理 (一部職業のみ追加能力&耐性、それ以外は反感&太古の怨念)
32  * @param player_ptr プレーヤーへの参照ポインタ
33  * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
34  * @param give_power 追加能力の有無
35  * @param give_resistance 追加耐性の有無
36  * @return そもそも対象のオブジェクトが恐怖の仮面ではないか、「その他の職業」であればTRUE
37  */
38 static bool invest_terror_mask(player_type *player_ptr, object_type *o_ptr, bool *give_power, bool *give_resistance)
39 {
40     if (o_ptr->name1 != ART_TERROR)
41         return FALSE;
42
43     bool is_special_class = player_ptr->pclass == CLASS_WARRIOR;
44     is_special_class |= player_ptr->pclass == CLASS_ARCHER;
45     is_special_class |= player_ptr->pclass == CLASS_CAVALRY;
46     is_special_class |= player_ptr->pclass == CLASS_BERSERKER;
47     if (is_special_class) {
48         *give_power = TRUE;
49         *give_resistance = TRUE;
50         return FALSE;
51     }
52
53     add_flag(o_ptr->art_flags, TR_AGGRAVATE);
54     add_flag(o_ptr->art_flags, TR_TY_CURSE);
55     o_ptr->curse_flags |= (TRC_CURSED | TRC_HEAVY_CURSE);
56     o_ptr->curse_flags |= get_curse(player_ptr, 2, o_ptr);
57     return TRUE;
58 }
59
60 /*!
61  * @brief 戦乙女ミリムの危ない水着への特殊処理 (セクシーギャルのみpval追加)
62  * @param player_ptr プレーヤーへの参照ポインタ
63  * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
64  * @return なし
65  */
66 static void milim_swimsuit(player_type *player_ptr, object_type *o_ptr)
67 {
68     if ((o_ptr->name1 != ART_MILIM) || (player_ptr->pseikaku != PERSONALITY_SEXY))
69         return;
70
71     o_ptr->pval = 3;
72     add_flag(o_ptr->art_flags, TR_STR);
73     add_flag(o_ptr->art_flags, TR_INT);
74     add_flag(o_ptr->art_flags, TR_WIS);
75     add_flag(o_ptr->art_flags, TR_DEX);
76     add_flag(o_ptr->art_flags, TR_CON);
77     add_flag(o_ptr->art_flags, TR_CHR);
78 }
79
80 /*!
81  * @brief 固定アーティファクト生成時の特別なハードコーディング処理を行う。.
82  * @details random_artifact_resistance()とあるが実際は固定アーティファクトである。
83  * 対象は恐怖の仮面、村正、ロビントンのハープ、龍争虎鬪、ブラッディムーン、羽衣、天女の羽衣、ミリム、
84  * その他追加耐性、特性追加処理。
85  * @attention プレイヤーの各種ステータスに依存した処理がある。
86  * @todo 折を見て関数名を変更すること。
87  * @param player_ptr プレーヤーへの参照ポインタ
88  * @param o_ptr 対象のオブジェクト構造体ポインタ
89  * @param a_ptr 生成する固定アーティファクト構造体ポインタ
90  * @return なし
91  */
92 static void random_artifact_resistance(player_type *player_ptr, object_type *o_ptr, artifact_type *a_ptr)
93 {
94     bool give_power = FALSE;
95     bool give_resistance = FALSE;
96     if (invest_terror_mask(player_ptr, o_ptr, &give_power, &give_resistance))
97         return;
98
99     if ((o_ptr->name1 == ART_MURAMASA) && (player_ptr->pclass != CLASS_SAMURAI)) {
100         add_flag(o_ptr->art_flags, TR_NO_MAGIC);
101         o_ptr->curse_flags |= (TRC_HEAVY_CURSE);
102     }
103
104     if ((o_ptr->name1 == ART_ROBINTON) && (player_ptr->pclass == CLASS_BARD))
105         add_flag(o_ptr->art_flags, TR_DEC_MANA);
106
107     if ((o_ptr->name1 == ART_XIAOLONG) && (player_ptr->pclass == CLASS_MONK))
108         add_flag(o_ptr->art_flags, TR_BLOWS);
109
110     if (o_ptr->name1 == ART_BLOOD)
111         get_bloody_moon_flags(o_ptr);
112
113     if ((o_ptr->name1 == ART_HEAVENLY_MAIDEN) && (player_ptr->psex != SEX_FEMALE))
114         add_flag(o_ptr->art_flags, TR_AGGRAVATE);
115
116     milim_swimsuit(player_ptr, o_ptr);
117     if (a_ptr->gen_flags.has(TRG::XTRA_POWER))
118         give_power = TRUE;
119
120     if (a_ptr->gen_flags.has(TRG::XTRA_H_RES))
121         give_resistance = TRUE;
122
123     if (a_ptr->gen_flags.has(TRG::XTRA_RES_OR_POWER)) {
124         if (one_in_(2))
125             give_resistance = TRUE;
126         else
127             give_power = TRUE;
128     }
129
130     if (give_power)
131         one_ability(o_ptr);
132
133     if (give_resistance)
134         one_high_resistance(o_ptr);
135
136     if (a_ptr->gen_flags.has(TRG::XTRA_DICE)) {
137         do {
138             o_ptr->dd++;
139         } while (one_in_(o_ptr->dd));
140
141         if (o_ptr->dd > 9)
142             o_ptr->dd = 9;
143     }
144 }
145
146 static void invest_curse_to_fixed_artifact(player_type *player_ptr, artifact_type *a_ptr, object_type *q_ptr)
147 {
148     if (a_ptr->gen_flags.has(TRG::CURSED))
149         q_ptr->curse_flags |= TRC_CURSED;
150
151     if (a_ptr->gen_flags.has(TRG::HEAVY_CURSE))
152         q_ptr->curse_flags |= TRC_HEAVY_CURSE;
153
154     if (a_ptr->gen_flags.has(TRG::PERMA_CURSE))
155         q_ptr->curse_flags |= TRC_PERMA_CURSE;
156
157     if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE0))
158         q_ptr->curse_flags |= get_curse(player_ptr, 0, q_ptr);
159
160     if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE1))
161         q_ptr->curse_flags |= get_curse(player_ptr, 1, q_ptr);
162
163     if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE2))
164         q_ptr->curse_flags |= get_curse(player_ptr, 2, q_ptr);
165 }
166
167 /*!
168  * @brief フロアの指定された位置に固定アーティファクトを生成する。 / Create the artifact of the specified number
169  * @details 固定アーティファクト構造体から基本ステータスをコピーした後、所定の座標でdrop_item()で落とす。
170  * @param player_ptr プレーヤーへの参照ポインタ
171  * @param a_idx 生成する固定アーティファクト構造体のID
172  * @param y アイテムを落とす地点のy座標
173  * @param x アイテムを落とす地点のx座標
174  * @return 生成が成功したか否か、失敗はIDの不全、ベースアイテムの不全、drop_item()の失敗時に起こる。
175  * @attention この処理はdrop_near()内で普通の固定アーティファクトが重ならない性質に依存する.
176  * 仮に2個以上存在可能かつ装備品以外の固定アーティファクトが作成されれば
177  * drop_near()関数の返り値は信用できなくなる.
178  */
179 bool create_named_art(player_type *player_ptr, ARTIFACT_IDX a_idx, POSITION y, POSITION x)
180 {
181     artifact_type *a_ptr = &a_info[a_idx];
182     if (!a_ptr->name)
183         return FALSE;
184
185     KIND_OBJECT_IDX i = lookup_kind(a_ptr->tval, a_ptr->sval);
186     if (i == 0)
187         return FALSE;
188
189     object_type forge;
190     object_type *q_ptr;
191     q_ptr = &forge;
192     object_prep(player_ptr, q_ptr, i);
193     q_ptr->name1 = a_idx;
194     q_ptr->pval = a_ptr->pval;
195     q_ptr->ac = a_ptr->ac;
196     q_ptr->dd = a_ptr->dd;
197     q_ptr->ds = a_ptr->ds;
198     q_ptr->to_a = a_ptr->to_a;
199     q_ptr->to_h = a_ptr->to_h;
200     q_ptr->to_d = a_ptr->to_d;
201     q_ptr->weight = a_ptr->weight;
202     invest_curse_to_fixed_artifact(player_ptr, a_ptr, q_ptr);
203     random_artifact_resistance(player_ptr, q_ptr, a_ptr);
204     return drop_near(player_ptr, q_ptr, -1, y, x) ? TRUE : FALSE;
205 }
206
207 /*!
208  * @brief 非INSTA_ART型の固定アーティファクトの生成を確率に応じて試行する。
209  * Mega-Hack -- Attempt to create one of the "Special Objects"
210  * @param player_ptr プレーヤーへの参照ポインタ
211  * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
212  * @return 生成に成功したらTRUEを返す。
213  * @details
214  * Attempt to change an object into an artifact\n
215  * This routine should only be called by "apply_magic()"\n
216  * Note -- see "make_artifact_special()" and "apply_magic()"\n
217  */
218 bool make_artifact(player_type *player_ptr, object_type *o_ptr)
219 {
220     floor_type *floor_ptr = player_ptr->current_floor_ptr;
221     if (floor_ptr->dun_level == 0)
222         return FALSE;
223
224     if (o_ptr->number != 1)
225         return FALSE;
226
227     for (ARTIFACT_IDX i = 0; i < max_a_idx; i++) {
228         artifact_type *a_ptr = &a_info[i];
229         if (!a_ptr->name)
230             continue;
231
232         if (a_ptr->cur_num)
233             continue;
234
235         if (a_ptr->gen_flags.has(TRG::QUESTITEM))
236             continue;
237
238         if (a_ptr->gen_flags.has(TRG::INSTA_ART))
239             continue;
240
241         if (a_ptr->tval != o_ptr->tval)
242             continue;
243
244         if (a_ptr->sval != o_ptr->sval)
245             continue;
246
247         if (a_ptr->level > floor_ptr->dun_level) {
248             int d = (a_ptr->level - floor_ptr->dun_level) * 2;
249             if (!one_in_(d))
250                 continue;
251         }
252
253         if (!one_in_(a_ptr->rarity))
254             continue;
255
256         o_ptr->name1 = i;
257         random_artifact_resistance(player_ptr, o_ptr, a_ptr);
258         return TRUE;
259     }
260
261     return FALSE;
262 }
263
264 /*!
265  * @brief INSTA_ART型の固定アーティファクトの生成を確率に応じて試行する。
266  * Mega-Hack -- Attempt to create one of the "Special Objects"
267  * @param player_ptr プレーヤーへの参照ポインタ
268  * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
269  * @return 生成に成功したらTRUEを返す。
270  * @details
271  * We are only called from "make_object()", and we assume that\n
272  * "apply_magic()" is called immediately after we return.\n
273  *\n
274  * Note -- see "make_artifact()" and "apply_magic()"\n
275  */
276 bool make_artifact_special(player_type *player_ptr, object_type *o_ptr)
277 {
278     KIND_OBJECT_IDX k_idx = 0;
279
280     /*! @note 地上ではキャンセルする / No artifacts in the town */
281     floor_type *floor_ptr = player_ptr->current_floor_ptr;
282     if (floor_ptr->dun_level == 0)
283         return FALSE;
284
285     /*! @note get_obj_num_hookによる指定がある場合は生成をキャンセルする / Themed object */
286     if (get_obj_num_hook)
287         return FALSE;
288
289     /*! @note 全固定アーティファクト中からIDの若い順に生成対象とその確率を走査する / Check the artifact list (just the "specials") */
290     for (ARTIFACT_IDX i = 0; i < max_a_idx; i++) {
291         artifact_type *a_ptr = &a_info[i];
292
293         /*! @note アーティファクト名が空の不正なデータは除外する / Skip "empty" artifacts */
294         if (!a_ptr->name)
295             continue;
296
297         /*! @note 既に生成回数がカウントされたアーティファクト、QUESTITEMと非INSTA_ARTは除外 / Cannot make an artifact twice */
298         if (a_ptr->cur_num)
299             continue;
300         if (a_ptr->gen_flags.has(TRG::QUESTITEM))
301             continue;
302         if (!(a_ptr->gen_flags.has(TRG::INSTA_ART)))
303             continue;
304
305         /*! @note アーティファクト生成階が現在に対して足りない場合は高確率で1/(不足階層*2)を満たさないと生成リストに加えられない /
306          *  XXX XXX Enforce minimum "depth" (loosely) */
307         if (a_ptr->level > floor_ptr->object_level) {
308             /* @note  / Acquire the "out-of-depth factor". Roll for out-of-depth creation. */
309             int d = (a_ptr->level - floor_ptr->object_level) * 2;
310             if (!one_in_(d))
311                 continue;
312         }
313
314         /*! @note 1/(レア度)の確率を満たさないと除外される / Artifact "rarity roll" */
315         if (!one_in_(a_ptr->rarity))
316             continue;
317
318         /*! @note INSTA_ART型固定アーティファクトのベースアイテムもチェック対象とする。ベースアイテムの生成階層が足りない場合1/(不足階層*5)
319          * を満たさないと除外される。 / Find the base object. XXX XXX Enforce minimum "object" level (loosely). Acquire the "out-of-depth factor". Roll for
320          * out-of-depth creation. */
321         k_idx = lookup_kind(a_ptr->tval, a_ptr->sval);
322         if (k_info[k_idx].level > floor_ptr->object_level) {
323             int d = (k_info[k_idx].level - floor_ptr->object_level) * 5;
324             if (!one_in_(d))
325                 continue;
326         }
327
328         /*! @note 前述の条件を満たしたら、後のIDのアーティファクトはチェックせずすぐ確定し生成処理に移す /
329          * Assign the template. Mega-Hack -- mark the item as an artifact. Hack: Some artifacts get random extra powers. Success. */
330         object_prep(player_ptr, o_ptr, k_idx);
331
332         o_ptr->name1 = i;
333         random_artifact_resistance(player_ptr, o_ptr, a_ptr);
334         return TRUE;
335     }
336
337     /*! @note 全INSTA_ART固定アーティファクトを試行しても決まらなかった場合 FALSEを返す / Failure */
338     return FALSE;
339 }