OSDN Git Service

Revert "Revert "Merge branch 'master' of git.osdn.net:/gitroot/hengband/hengband""
[hengband/hengband.git] / src / inventory / inventory-curse.c
1 #include "inventory/inventory-curse.h"
2 #include "art-definition/art-accessory-types.h"
3 #include "core/asking-player.h"
4 #include "core/disturbance.h"
5 #include "core/player-redraw-types.h"
6 #include "core/player-update-types.h"
7 #include "flavor/flavor-describer.h"
8 #include "flavor/object-flavor-types.h"
9 #include "inventory/inventory-slot-types.h"
10 #include "io/files-util.h"
11 #include "monster-floor/monster-summon.h"
12 #include "monster-floor/place-monster-types.h"
13 #include "object-enchant/item-feeling.h"
14 #include "object-enchant/object-curse.h"
15 #include "object-enchant/special-object-flags.h"
16 #include "object-enchant/tr-types.h"
17 #include "object-enchant/trc-types.h"
18 #include "object/object-flags.h"
19 #include "perception/object-perception.h"
20 #include "player/player-damage.h"
21 #include "player/player-race-types.h"
22 #include "spell-kind/spells-random.h"
23 #include "spell-kind/spells-teleport.h"
24 #include "spell/summon-types.h"
25 #include "status/bad-status-setter.h"
26 #include "system/floor-type-definition.h"
27 #include "util/bit-flags-calculator.h"
28 #include "util/quarks.h"
29 #include "util/string-processor.h"
30 #include "view/display-messages.h"
31
32 #define TRC_P_FLAG_MASK                                                                                                                                        \
33     (TRC_TELEPORT_SELF | TRC_CHAINSWORD | TRC_TY_CURSE | TRC_DRAIN_EXP | TRC_ADD_L_CURSE | TRC_ADD_H_CURSE | TRC_CALL_ANIMAL | TRC_CALL_DEMON                  \
34         | TRC_CALL_DRAGON | TRC_COWARDICE | TRC_TELEPORT | TRC_DRAIN_HP | TRC_DRAIN_MANA | TRC_CALL_UNDEAD)
35
36 static bool is_specific_curse(BIT_FLAGS flag)
37 {
38     return (flag == TRC_ADD_L_CURSE) || (flag == TRC_ADD_H_CURSE) || (flag == TRC_DRAIN_HP) || (flag == TRC_DRAIN_MANA) || (flag == TRC_CALL_ANIMAL)
39         || (flag == TRC_CALL_DEMON) || (flag == TRC_CALL_DRAGON) || (flag == TRC_CALL_UNDEAD) || (flag == TRC_COWARDICE) || (flag == TRC_LOW_MELEE)
40         || (flag == TRC_LOW_AC) || (flag == TRC_LOW_MAGIC) || (flag == TRC_FAST_DIGEST) || (flag == TRC_SLOW_REGEN);
41 }
42
43 static void choise_cursed_item(player_type *creature_ptr, BIT_FLAGS flag, object_type *o_ptr, int *choices, int *number, int item_num)
44 {
45     if (!is_specific_curse(flag))
46         return;
47
48     tr_type cf = 0;
49     BIT_FLAGS flgs[TR_FLAG_SIZE];
50     object_flags(creature_ptr, o_ptr, flgs);
51     switch (flag) {
52     case TRC_ADD_L_CURSE:
53         cf = TR_ADD_L_CURSE;
54         break;
55     case TRC_ADD_H_CURSE:
56         cf = TR_ADD_H_CURSE;
57         break;
58     case TRC_DRAIN_HP:
59         cf = TR_DRAIN_HP;
60         break;
61     case TRC_DRAIN_MANA:
62         cf = TR_DRAIN_MANA;
63         break;
64     case TRC_CALL_ANIMAL:
65         cf = TR_CALL_ANIMAL;
66         break;
67     case TRC_CALL_DEMON:
68         cf = TR_CALL_DEMON;
69         break;
70     case TRC_CALL_DRAGON:
71         cf = TR_CALL_DRAGON;
72         break;
73     case TRC_CALL_UNDEAD:
74         cf = TR_CALL_UNDEAD;
75         break;
76     case TRC_COWARDICE:
77         cf = TR_COWARDICE;
78         break;
79     case TRC_LOW_MELEE:
80         cf = TR_LOW_MELEE;
81         break;
82     case TRC_LOW_AC:
83         cf = TR_LOW_AC;
84         break;
85     case TRC_LOW_MAGIC:
86         cf = TR_LOW_MAGIC;
87         break;
88     case TRC_FAST_DIGEST:
89         cf = TR_FAST_DIGEST;
90         break;
91     case TRC_SLOW_REGEN:
92         cf = TR_SLOW_REGEN;
93         break;
94     default:
95         break;
96     }
97
98     if (!have_flag(flgs, (long)cf))
99         return;
100
101     choices[*number] = item_num;
102     (*number)++;
103 }
104
105 /*!
106  * @brief 現在呪いを保持している装備品を一つランダムに探し出す / Choose one of items that have cursed flag
107  * @param flag 探し出したい呪いフラグ配列
108  * @return 該当の呪いが一つでもあった場合にランダムに選ばれた装備品のオブジェクト構造体参照ポインタを返す。\n
109  * 呪いがない場合NULLを返す。
110  */
111 object_type *choose_cursed_obj_name(player_type *creature_ptr, BIT_FLAGS flag)
112 {
113     int choices[INVEN_TOTAL - INVEN_RARM];
114     int number = 0;
115     if (!(creature_ptr->cursed & flag))
116         return NULL;
117
118     for (inventory_slot_type i = INVEN_RARM; i < INVEN_TOTAL; i++) {
119         object_type *o_ptr = &creature_ptr->inventory_list[i];
120         if (o_ptr->curse_flags & flag) {
121             choices[number] = i;
122             number++;
123             continue;
124         }
125
126         choise_cursed_item(creature_ptr, flag, o_ptr, choices, &number, i);
127     }
128
129     return &creature_ptr->inventory_list[choices[randint0(number)]];
130 }
131
132 /*!
133  * @brief 呪われている、トランプエゴ等による装備品由来のテレポートを実行する
134  * @param creature_ptr プレーヤーへの参照ポインタ
135  * @return なし
136  */
137 static void curse_teleport(player_type *creature_ptr)
138 {
139     if (((creature_ptr->cursed & TRC_TELEPORT_SELF) == 0) || !one_in_(200))
140         return;
141
142     GAME_TEXT o_name[MAX_NLEN];
143     object_type *o_ptr;
144     int i_keep = 0, count = 0;
145     for (inventory_slot_type i = INVEN_RARM; i < INVEN_TOTAL; i++) {
146         BIT_FLAGS flgs[TR_FLAG_SIZE];
147         o_ptr = &creature_ptr->inventory_list[i];
148         if (!o_ptr->k_idx)
149             continue;
150
151         object_flags(creature_ptr, o_ptr, flgs);
152
153         if (!have_flag(flgs, TR_TELEPORT))
154             continue;
155
156         if (o_ptr->inscription && angband_strchr(quark_str(o_ptr->inscription), '.'))
157             continue;
158
159         count++;
160         if (one_in_(count))
161             i_keep = i;
162     }
163
164     o_ptr = &creature_ptr->inventory_list[i_keep];
165     describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
166     msg_format(_("%sがテレポートの能力を発動させようとしている。", "Your %s is activating teleportation."), o_name);
167     if (get_check_strict(creature_ptr, _("テレポートしますか?", "Teleport? "), CHECK_OKAY_CANCEL)) {
168         disturb(creature_ptr, FALSE, TRUE);
169         teleport_player(creature_ptr, 50, TELEPORT_SPONTANEOUS);
170     } else {
171         msg_format(_("%sに{.}(ピリオド)と銘を刻むと発動を抑制できます。", "You can inscribe {.} on your %s to disable random teleportation. "), o_name);
172         disturb(creature_ptr, TRUE, TRUE);
173     }
174 }
175
176 /*!
177  * @details 元々呪い効果の発揮ルーチン中にいたので、整合性保持のためここに置いておく
178  */
179 static void occur_chainsword_effect(player_type *creature_ptr)
180 {
181     if (((creature_ptr->cursed & TRC_CHAINSWORD) == 0) || !one_in_(CHAINSWORD_NOISE))
182         return;
183
184     char noise[1024];
185     if (!get_rnd_line(_("chainswd_j.txt", "chainswd.txt"), 0, noise))
186         msg_print(noise);
187     disturb(creature_ptr, FALSE, FALSE);
188 }
189
190 static void curse_drain_exp(player_type *creature_ptr)
191 {
192     if ((creature_ptr->prace == RACE_ANDROID) || ((creature_ptr->cursed & TRC_DRAIN_EXP) == 0) || !one_in_(4))
193         return;
194
195     creature_ptr->exp -= (creature_ptr->lev + 1) / 2;
196     if (creature_ptr->exp < 0)
197         creature_ptr->exp = 0;
198
199     creature_ptr->max_exp -= (creature_ptr->lev + 1) / 2;
200     if (creature_ptr->max_exp < 0)
201         creature_ptr->max_exp = 0;
202
203     check_experience(creature_ptr);
204 }
205
206 static void multiply_low_curse(player_type *creature_ptr)
207 {
208     if (((creature_ptr->cursed & TRC_ADD_L_CURSE) == 0) || !one_in_(2000))
209         return;
210
211     object_type *o_ptr;
212     o_ptr = choose_cursed_obj_name(creature_ptr, TRC_ADD_L_CURSE);
213     BIT_FLAGS new_curse = get_curse(creature_ptr, 0, o_ptr);
214     if ((o_ptr->curse_flags & new_curse))
215         return;
216
217     GAME_TEXT o_name[MAX_NLEN];
218     describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
219     o_ptr->curse_flags |= new_curse;
220     msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), o_name);
221     o_ptr->feeling = FEEL_NONE;
222     creature_ptr->update |= (PU_BONUS);
223 }
224
225 static void multiply_high_curse(player_type *creature_ptr)
226 {
227     if (((creature_ptr->cursed & TRC_ADD_H_CURSE) == 0) || !one_in_(2000))
228         return;
229
230     object_type *o_ptr;
231     o_ptr = choose_cursed_obj_name(creature_ptr, TRC_ADD_H_CURSE);
232     BIT_FLAGS new_curse = get_curse(creature_ptr, 1, o_ptr);
233     if ((o_ptr->curse_flags & new_curse))
234         return;
235
236     GAME_TEXT o_name[MAX_NLEN];
237     describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
238     o_ptr->curse_flags |= new_curse;
239     msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), o_name);
240     o_ptr->feeling = FEEL_NONE;
241     creature_ptr->update |= (PU_BONUS);
242 }
243
244 static void curse_call_monster(player_type *creature_ptr)
245 {
246     const int call_type = PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET;
247     const int obj_desc_type = OD_OMIT_PREFIX | OD_NAME_ONLY;
248     floor_type *floor_ptr = creature_ptr->current_floor_ptr;
249     if ((creature_ptr->cursed & TRC_CALL_ANIMAL) && one_in_(2500)) {
250         if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_ANIMAL, call_type)) {
251             GAME_TEXT o_name[MAX_NLEN];
252             describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC_CALL_ANIMAL), obj_desc_type);
253             msg_format(_("%sが動物を引き寄せた!", "Your %s has attracted an animal!"), o_name);
254             disturb(creature_ptr, FALSE, TRUE);
255         }
256     }
257
258     if ((creature_ptr->cursed & TRC_CALL_DEMON) && one_in_(1111)) {
259         if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_DEMON, call_type)) {
260             GAME_TEXT o_name[MAX_NLEN];
261             describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC_CALL_DEMON), obj_desc_type);
262             msg_format(_("%sが悪魔を引き寄せた!", "Your %s has attracted a demon!"), o_name);
263             disturb(creature_ptr, FALSE, TRUE);
264         }
265     }
266
267     if ((creature_ptr->cursed & TRC_CALL_DRAGON) && one_in_(800)) {
268         if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_DRAGON, call_type)) {
269             GAME_TEXT o_name[MAX_NLEN];
270             describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC_CALL_DRAGON), obj_desc_type);
271             msg_format(_("%sがドラゴンを引き寄せた!", "Your %s has attracted an dragon!"), o_name);
272             disturb(creature_ptr, FALSE, TRUE);
273         }
274     }
275
276     if ((creature_ptr->cursed & TRC_CALL_UNDEAD) && one_in_(1111)) {
277         if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_UNDEAD, call_type)) {
278             GAME_TEXT o_name[MAX_NLEN];
279             describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC_CALL_UNDEAD), obj_desc_type);
280             msg_format(_("%sが死霊を引き寄せた!", "Your %s has attracted an undead!"), o_name);
281             disturb(creature_ptr, FALSE, TRUE);
282         }
283     }
284 }
285
286 static void curse_cowardice(player_type *creature_ptr)
287 {
288     if (((creature_ptr->cursed & TRC_COWARDICE) == 0) || !one_in_(1500))
289         return;
290
291     if (creature_ptr->resist_fear)
292         return;
293
294     disturb(creature_ptr, FALSE, TRUE);
295     msg_print(_("とても暗い... とても恐い!", "It's so dark... so scary!"));
296     set_afraid(creature_ptr, creature_ptr->afraid + 13 + randint1(26));
297 }
298
299 static void curse_drain_hp(player_type *creature_ptr)
300 {
301     if (((creature_ptr->cursed & TRC_DRAIN_HP) == 0) || !one_in_(666))
302         return;
303
304     GAME_TEXT o_name[MAX_NLEN];
305     describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC_DRAIN_HP), (OD_OMIT_PREFIX | OD_NAME_ONLY));
306     msg_format(_("%sはあなたの体力を吸収した!", "Your %s drains HP from you!"), o_name);
307     take_hit(creature_ptr, DAMAGE_LOSELIFE, MIN(creature_ptr->lev * 2, 100), o_name, -1);
308 }
309
310 static void curse_drain_mp(player_type *creature_ptr)
311 {
312     if (((creature_ptr->cursed & TRC_DRAIN_MANA) == 0) || (creature_ptr->csp == 0) || !one_in_(666))
313         return;
314
315     GAME_TEXT o_name[MAX_NLEN];
316     describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC_DRAIN_MANA), (OD_OMIT_PREFIX | OD_NAME_ONLY));
317     msg_format(_("%sはあなたの魔力を吸収した!", "Your %s drains mana from you!"), o_name);
318     creature_ptr->csp -= MIN(creature_ptr->lev, 50);
319     if (creature_ptr->csp < 0) {
320         creature_ptr->csp = 0;
321         creature_ptr->csp_frac = 0;
322     }
323
324     creature_ptr->redraw |= PR_MANA;
325 }
326
327 static void occur_curse_effects(player_type *creature_ptr)
328 {
329     if (((creature_ptr->cursed & TRC_P_FLAG_MASK) == 0) || creature_ptr->phase_out || creature_ptr->wild_mode)
330         return;
331
332     curse_teleport(creature_ptr);
333     occur_chainsword_effect(creature_ptr);
334     if ((creature_ptr->cursed & TRC_TY_CURSE) && one_in_(TY_CURSE_CHANCE)) {
335         int count = 0;
336         (void)activate_ty_curse(creature_ptr, FALSE, &count);
337     }
338
339     curse_drain_exp(creature_ptr);
340     multiply_low_curse(creature_ptr);
341     multiply_high_curse(creature_ptr);
342     curse_call_monster(creature_ptr);
343     curse_cowardice(creature_ptr);
344     if ((creature_ptr->cursed & TRC_TELEPORT) && one_in_(200) && !creature_ptr->anti_tele) {
345         disturb(creature_ptr, FALSE, TRUE);
346         teleport_player(creature_ptr, 40, TELEPORT_PASSIVE);
347     }
348
349     curse_drain_hp(creature_ptr);
350     curse_drain_mp(creature_ptr);
351 }
352
353 /*!
354  * @brief 10ゲームターンが進行するごとに装備効果の発動判定を行う処理
355  * / Handle curse effects once every 10 game turns
356  * @param creature_ptr プレーヤーへの参照ポインタ
357  * @return なし
358  */
359 void execute_cursed_items_effect(player_type *creature_ptr)
360 {
361     occur_curse_effects(creature_ptr);
362     if (!one_in_(999) || creature_ptr->anti_magic)
363         return;
364
365     object_type *o_ptr = &creature_ptr->inventory_list[INVEN_LITE];
366     if (o_ptr->name1 != ART_JUDGE)
367         return;
368
369     if (object_is_known(o_ptr))
370         msg_print(_("『審判の宝石』はあなたの体力を吸収した!", "The Jewel of Judgement drains life from you!"));
371     else
372         msg_print(_("なにかがあなたの体力を吸収した!", "Something drains life from you!"));
373
374     take_hit(creature_ptr, DAMAGE_LOSELIFE, MIN(creature_ptr->lev, 50), _("審判の宝石", "the Jewel of Judgement"), -1);
375 }