OSDN Git Service

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