OSDN Git Service

Merge pull request #1471 from sikabane-works/release/3.0.0Alpha37
[hengbandforosx/hengbandosx.git] / src / artifact / fixed-art-generator.cpp
1 /*!
2  * @file fixed-art-generator.cpp
3  * @brief 固定アーティファクトの生成 / Artifact code
4  * @date 2020/07/14
5  * @author
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
12  */
13
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"
32
33 /*!
34  * @brief 恐怖の仮面への特殊処理
35  * @param player_ptr プレーヤーへの参照ポインタ
36  * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
37  * @return 追加能力/耐性がもらえるならtrue、もらえないならfalse
38  * @details
39  * 純戦士系職業は追加能力/耐性がもらえる。
40  * それ以外では、反感、太古の怨念、呪いが付き追加能力/耐性はもらえない。
41  */
42 static bool invest_terror_mask(player_type *player_ptr, object_type *o_ptr)
43 {
44     if (o_ptr->name1 != ART_TERROR)
45         return false;
46
47     switch (player_ptr->pclass) {
48     case CLASS_WARRIOR:
49     case CLASS_ARCHER:
50     case CLASS_CAVALRY:
51     case CLASS_BERSERKER:
52         return true;
53     default:
54         add_flag(o_ptr->art_flags, TR_AGGRAVATE);
55         add_flag(o_ptr->art_flags, 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));
58         return false;
59     }
60 }
61
62 /*!
63  * @brief 戦乙女ミリムの危ない水着への特殊処理 (セクシーギャルのみpval追加)
64  * @param player_ptr プレーヤーへの参照ポインタ
65  * @param o_ptr 対象のオブジェクト構造体への参照ポインタ
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  * @attention プレイヤーの各種ステータスに依存した処理がある。
84  * @todo 折を見て関数名を変更すること。
85  * @param player_ptr プレーヤーへの参照ポインタ
86  * @param o_ptr 対象のオブジェクト構造体ポインタ
87  * @param a_ptr 生成する固定アーティファクト構造体ポインタ
88  * @details
89  * 対象は村正、ロビントンのハープ、龍争虎鬪、ブラッディムーン、羽衣、天女の羽衣、ミリム
90  */
91 static void invest_special_artifact_abilities(player_type *player_ptr, object_type *o_ptr)
92 {
93     switch (o_ptr->name1) {
94     case ART_MURAMASA:
95         if (player_ptr->pclass != CLASS_SAMURAI) {
96             add_flag(o_ptr->art_flags, TR_NO_MAGIC);
97             o_ptr->curse_flags.set(TRC::HEAVY_CURSE);
98         }
99         return;
100     case ART_ROBINTON:
101         if (player_ptr->pclass == CLASS_BARD)
102             add_flag(o_ptr->art_flags, TR_DEC_MANA);
103         return;
104     case ART_XIAOLONG:
105         if (player_ptr->pclass == CLASS_MONK)
106             add_flag(o_ptr->art_flags, TR_BLOWS);
107         return;
108     case ART_BLOOD:
109         get_bloody_moon_flags(o_ptr);
110         return;
111     case ART_HEAVENLY_MAIDEN:
112         if (player_ptr->psex != SEX_FEMALE)
113             add_flag(o_ptr->art_flags, TR_AGGRAVATE);
114         return;
115     case ART_MILIM:
116         milim_swimsuit(player_ptr, o_ptr);
117         return;
118     default:
119         break;
120     }
121 }
122
123 /*!
124  * @brief 固定アーティファクトオブジェクトに追加能力/耐性を付加する
125  * @param player_ptr プレイヤー情報への参照ポインタ
126  * @param a_ptr 固定アーティファクト情報への参照ポインタ
127  * @param q_ptr オブジェクト情報への参照ポインタ
128  */
129 static void fixed_artifact_random_abilities(player_type *player_ptr, artifact_type *a_ptr, object_type *o_ptr)
130 {
131     auto give_power = false;
132     auto give_resistance = false;
133
134     if (invest_terror_mask(player_ptr, o_ptr)) {
135         give_power = true;
136         give_resistance = true;
137     }
138
139     invest_special_artifact_abilities(player_ptr, o_ptr);
140
141     if (a_ptr->gen_flags.has(TRG::XTRA_POWER))
142         give_power = true;
143
144     if (a_ptr->gen_flags.has(TRG::XTRA_H_RES))
145         give_resistance = true;
146
147     if (a_ptr->gen_flags.has(TRG::XTRA_RES_OR_POWER)) {
148         if (one_in_(2))
149             give_resistance = true;
150         else
151             give_power = true;
152     }
153
154     if (give_power)
155         one_ability(o_ptr);
156
157     if (give_resistance)
158         one_high_resistance(o_ptr);
159
160     if (a_ptr->gen_flags.has(TRG::XTRA_DICE)) {
161         do {
162             o_ptr->dd++;
163         } while (one_in_(o_ptr->dd));
164
165         if (o_ptr->dd > 9)
166             o_ptr->dd = 9;
167     }
168 }
169
170 /*!
171  * @brief 固定アーティファクトオブジェクトに呪いフラグを付加する
172  * @param player_ptr プレイヤー情報への参照ポインタ
173  * @param a_ptr 固定アーティファクト情報への参照ポインタ
174  * @param q_ptr オブジェクト情報への参照ポインタ
175  */
176 static void invest_curse_to_fixed_artifact(artifact_type *a_ptr, object_type *o_ptr)
177 {
178     if (!a_ptr->cost)
179         set_bits(o_ptr->ident, IDENT_BROKEN);
180
181     if (a_ptr->gen_flags.has(TRG::CURSED))
182         o_ptr->curse_flags.set(TRC::CURSED);
183
184     if (a_ptr->gen_flags.has(TRG::HEAVY_CURSE))
185         o_ptr->curse_flags.set(TRC::HEAVY_CURSE);
186
187     if (a_ptr->gen_flags.has(TRG::PERMA_CURSE))
188         o_ptr->curse_flags.set(TRC::PERMA_CURSE);
189
190     if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE0))
191         o_ptr->curse_flags.set(get_curse(0, o_ptr));
192
193     if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE1))
194         o_ptr->curse_flags.set(get_curse(1, o_ptr));
195
196     if (a_ptr->gen_flags.has(TRG::RANDOM_CURSE2))
197         o_ptr->curse_flags.set(get_curse(2, o_ptr));
198 }
199
200 /*!
201  * @brief オブジェクトに指定した固定アーティファクトをオブジェクトに割り当てる。
202  * @param player_ptr プレーヤーへの参照ポインタ
203  * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
204  * @return 適用したアーティファクト情報への参照ポインタ
205  */
206 artifact_type *apply_artifact(player_type *player_ptr, object_type *o_ptr)
207 {
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;
218
219     invest_curse_to_fixed_artifact(a_ptr, o_ptr);
220     fixed_artifact_random_abilities(player_ptr, a_ptr, o_ptr);
221
222     return a_ptr;
223 }
224
225 /*!
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()関数の返り値は信用できなくなる.
236  */
237 bool create_named_art(player_type *player_ptr, ARTIFACT_IDX a_idx, POSITION y, POSITION x)
238 {
239     auto a_ptr = &a_info[a_idx];
240     if (a_ptr->name.empty())
241         return false;
242
243     auto i = lookup_kind(a_ptr->tval, a_ptr->sval);
244     if (i == 0)
245         return true;
246
247     object_type forge;
248     auto q_ptr = &forge;
249     q_ptr->prep(i);
250     q_ptr->name1 = a_idx;
251
252     (void)apply_artifact(player_ptr, q_ptr);
253
254     return drop_near(player_ptr, q_ptr, -1, y, x) ? true : false;
255 }
256
257 /*!
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を返す。
263  * @details
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
267  */
268 bool make_artifact(player_type *player_ptr, object_type *o_ptr)
269 {
270     auto floor_ptr = player_ptr->current_floor_ptr;
271     if (floor_ptr->dun_level == 0)
272         return false;
273
274     if (o_ptr->number != 1)
275         return false;
276
277     for (ARTIFACT_IDX i = 0; i < max_a_idx; i++) {
278         auto a_ptr = &a_info[i];
279
280         if (a_ptr->name.empty())
281             continue;
282
283         if (a_ptr->cur_num)
284             continue;
285
286         if (a_ptr->gen_flags.has(TRG::QUESTITEM))
287             continue;
288
289         if (a_ptr->gen_flags.has(TRG::INSTA_ART))
290             continue;
291
292         if (a_ptr->tval != o_ptr->tval)
293             continue;
294
295         if (a_ptr->sval != o_ptr->sval)
296             continue;
297
298         if (a_ptr->level > floor_ptr->dun_level) {
299             int d = (a_ptr->level - floor_ptr->dun_level) * 2;
300             if (!one_in_(d))
301                 continue;
302         }
303
304         if (!one_in_(a_ptr->rarity))
305             continue;
306
307         o_ptr->name1 = i;
308         return true;
309     }
310
311     return false;
312 }
313
314 /*!
315  * @brief INSTA_ART型の固定アーティファクトの生成を確率に応じて試行する。
316  * Mega-Hack -- Attempt to create one of the "Special Objects"
317  * @param player_ptr プレーヤーへの参照ポインタ
318  * @param o_ptr 生成に割り当てたいオブジェクトの構造体参照ポインタ
319  * @return 生成に成功したらTRUEを返す。
320  * @details
321  * We are only called from "make_object()", and we assume that\n
322  * "apply_magic()" is called immediately after we return.\n
323  *\n
324  * Note -- see "make_artifact()" and "apply_magic()"\n
325  */
326 bool make_artifact_special(player_type *player_ptr, object_type *o_ptr)
327 {
328     KIND_OBJECT_IDX k_idx = 0;
329
330     /*! @note 地上ではキャンセルする / No artifacts in the town */
331     auto floor_ptr = player_ptr->current_floor_ptr;
332     if (floor_ptr->dun_level == 0)
333         return false;
334
335     /*! @note get_obj_num_hookによる指定がある場合は生成をキャンセルする / Themed object */
336     if (get_obj_num_hook)
337         return false;
338
339     /*! @note 全固定アーティファクト中からIDの若い順に生成対象とその確率を走査する / Check the artifact list (just the "specials") */
340     for (ARTIFACT_IDX i = 0; i < max_a_idx; i++) {
341         auto a_ptr = &a_info[i];
342
343         /*! @note アーティファクト名が空の不正なデータは除外する / Skip "empty" artifacts */
344         if (a_ptr->name.empty())
345             continue;
346
347         /*! @note 既に生成回数がカウントされたアーティファクト、QUESTITEMと非INSTA_ARTは除外 / Cannot make an artifact twice */
348         if (a_ptr->cur_num)
349             continue;
350         if (a_ptr->gen_flags.has(TRG::QUESTITEM))
351             continue;
352         if (!(a_ptr->gen_flags.has(TRG::INSTA_ART)))
353             continue;
354
355         /*! @note アーティファクト生成階が現在に対して足りない場合は高確率で1/(不足階層*2)を満たさないと生成リストに加えられない /
356          *  XXX XXX Enforce minimum "depth" (loosely) */
357         if (a_ptr->level > floor_ptr->object_level) {
358             /* @note  / Acquire the "out-of-depth factor". Roll for out-of-depth creation. */
359             int d = (a_ptr->level - floor_ptr->object_level) * 2;
360             if (!one_in_(d))
361                 continue;
362         }
363
364         /*! @note 1/(レア度)の確率を満たさないと除外される / Artifact "rarity roll" */
365         if (!one_in_(a_ptr->rarity))
366             continue;
367
368         /*! @note INSTA_ART型固定アーティファクトのベースアイテムもチェック対象とする。ベースアイテムの生成階層が足りない場合1/(不足階層*5)
369          * を満たさないと除外される。 / Find the base object. XXX XXX Enforce minimum "object" level (loosely). Acquire the "out-of-depth factor". Roll for
370          * out-of-depth creation. */
371         k_idx = lookup_kind(a_ptr->tval, a_ptr->sval);
372         if (k_info[k_idx].level > floor_ptr->object_level) {
373             int d = (k_info[k_idx].level - floor_ptr->object_level) * 5;
374             if (!one_in_(d))
375                 continue;
376         }
377
378         /*! @note 前述の条件を満たしたら、後のIDのアーティファクトはチェックせずすぐ確定し生成処理に移す /
379          * Assign the template. Mega-Hack -- mark the item as an artifact. Hack: Some artifacts get random extra powers. Success. */
380         o_ptr->prep(k_idx);
381
382         o_ptr->name1 = i;
383         return true;
384     }
385
386     /*! @note 全INSTA_ART固定アーティファクトを試行しても決まらなかった場合 FALSEを返す / Failure */
387     return false;
388 }