1 #include "inventory/inventory-curse.h"
2 #include "artifact/fixed-art-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 "player/player-status-flags.h"
23 #include "player/player-status.h"
24 #include "spell-kind/spells-random.h"
25 #include "spell-kind/spells-teleport.h"
26 #include "spell/summon-types.h"
27 #include "status/bad-status-setter.h"
28 #include "status/buff-setter.h"
29 #include "system/floor-type-definition.h"
30 #include "system/object-type-definition.h"
31 #include "system/player-type-definition.h"
32 #include "util/bit-flags-calculator.h"
33 #include "util/quarks.h"
34 #include "util/string-processor.h"
35 #include "view/display-messages.h"
38 const EnumClassFlagGroup<TRC> TRC_P_FLAG_MASK({ TRC::TY_CURSE, TRC::DRAIN_EXP, TRC::ADD_L_CURSE, TRC::ADD_H_CURSE, TRC::CALL_ANIMAL, TRC::CALL_DEMON, TRC::CALL_DRAGON,
39 TRC::COWARDICE, TRC::TELEPORT, TRC::DRAIN_HP, TRC::DRAIN_MANA, TRC::CALL_UNDEAD, TRC::BERS_RAGE });
40 const EnumClassFlagGroup<TRCS> TRCS_P_FLAG_MASK({ TRCS::TELEPORT_SELF, TRCS::CHAINSWORD });
43 static bool is_specific_curse(TRC flag)
46 case TRC::ADD_L_CURSE:
47 case TRC::ADD_H_CURSE:
50 case TRC::CALL_ANIMAL:
52 case TRC::CALL_DRAGON:
53 case TRC::CALL_UNDEAD:
58 case TRC::FAST_DIGEST:
67 static void choise_cursed_item(TRC flag, object_type *o_ptr, int *choices, int *number, int item_num)
69 if (!is_specific_curse(flag))
74 object_flags(o_ptr, flgs);
76 case TRC::ADD_L_CURSE:
79 case TRC::ADD_H_CURSE:
88 case TRC::CALL_ANIMAL:
94 case TRC::CALL_DRAGON:
97 case TRC::CALL_UNDEAD:
109 case TRC::HARD_SPELL:
112 case TRC::FAST_DIGEST:
115 case TRC::SLOW_REGEN:
125 if (!has_flag(flgs, (long)cf))
128 choices[*number] = item_num;
133 * @brief 現在呪いを保持している装備品を一つランダムに探し出す / Choose one of items that have cursed flag
134 * @param flag 探し出したい呪いフラグ配列
135 * @return 該当の呪いが一つでもあった場合にランダムに選ばれた装備品のオブジェクト構造体参照ポインタを返す。\n
138 object_type *choose_cursed_obj_name(player_type *creature_ptr, TRC flag)
140 int choices[INVEN_TOTAL - INVEN_MAIN_HAND];
142 if (creature_ptr->cursed.has_not(flag))
145 for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
146 object_type *o_ptr = &creature_ptr->inventory_list[i];
147 if (o_ptr->curse_flags.has(flag)) {
153 choise_cursed_item(flag, o_ptr, choices, &number, i);
156 return &creature_ptr->inventory_list[choices[randint0(number)]];
160 * @brief 呪われている、トランプエゴ等による装備品由来のテレポートを実行する
161 * @param creature_ptr プレーヤーへの参照ポインタ
163 static void curse_teleport(player_type *creature_ptr)
165 if ((creature_ptr->cursed_special.has_not(TRCS::TELEPORT_SELF)) || !one_in_(200))
168 GAME_TEXT o_name[MAX_NLEN];
170 int i_keep = 0, count = 0;
171 for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
173 o_ptr = &creature_ptr->inventory_list[i];
177 object_flags(o_ptr, flgs);
179 if (!has_flag(flgs, TR_TELEPORT))
182 if (o_ptr->inscription && angband_strchr(quark_str(o_ptr->inscription), '.'))
190 o_ptr = &creature_ptr->inventory_list[i_keep];
191 describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
192 msg_format(_("%sがテレポートの能力を発動させようとしている。", "Your %s tries to teleport you."), o_name);
193 if (get_check_strict(creature_ptr, _("テレポートしますか?", "Teleport? "), CHECK_OKAY_CANCEL)) {
194 disturb(creature_ptr, false, true);
195 teleport_player(creature_ptr, 50, TELEPORT_SPONTANEOUS);
197 msg_format(_("%sに{.}(ピリオド)と銘を刻むと発動を抑制できます。", "You can inscribe {.} on your %s to disable random teleportation. "), o_name);
198 disturb(creature_ptr, true, true);
203 * @details 元々呪い効果の発揮ルーチン中にいたので、整合性保持のためここに置いておく
205 static void occur_chainsword_effect(player_type *creature_ptr)
207 if ((creature_ptr->cursed_special.has_not(TRCS::CHAINSWORD)) || !one_in_(CHAINSWORD_NOISE))
211 if (!get_rnd_line(_("chainswd_j.txt", "chainswd.txt"), 0, noise))
213 disturb(creature_ptr, false, false);
216 static void curse_drain_exp(player_type *creature_ptr)
218 if ((creature_ptr->prace == player_race_type::ANDROID) || (creature_ptr->cursed.has_not(TRC::DRAIN_EXP)) || !one_in_(4))
221 creature_ptr->exp -= (creature_ptr->lev + 1) / 2;
222 if (creature_ptr->exp < 0)
223 creature_ptr->exp = 0;
225 creature_ptr->max_exp -= (creature_ptr->lev + 1) / 2;
226 if (creature_ptr->max_exp < 0)
227 creature_ptr->max_exp = 0;
229 check_experience(creature_ptr);
232 static void multiply_low_curse(player_type *creature_ptr)
234 if ((creature_ptr->cursed.has_not(TRC::ADD_L_CURSE)) || !one_in_(2000))
238 o_ptr = choose_cursed_obj_name(creature_ptr, TRC::ADD_L_CURSE);
239 auto new_curse = get_curse(0, o_ptr);
240 if (o_ptr->curse_flags.has(new_curse))
243 GAME_TEXT o_name[MAX_NLEN];
244 describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
245 o_ptr->curse_flags.set(new_curse);
246 msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), o_name);
247 o_ptr->feeling = FEEL_NONE;
248 creature_ptr->update |= (PU_BONUS);
251 static void multiply_high_curse(player_type *creature_ptr)
253 if ((creature_ptr->cursed.has_not(TRC::ADD_H_CURSE)) || !one_in_(2000))
257 o_ptr = choose_cursed_obj_name(creature_ptr, TRC::ADD_H_CURSE);
258 auto new_curse = get_curse(1, o_ptr);
259 if (o_ptr->curse_flags.has(new_curse))
262 GAME_TEXT o_name[MAX_NLEN];
263 describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
264 o_ptr->curse_flags.set(new_curse);
265 msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), o_name);
266 o_ptr->feeling = FEEL_NONE;
267 creature_ptr->update |= (PU_BONUS);
270 static void curse_call_monster(player_type *creature_ptr)
272 const int call_type = PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_NO_PET;
273 const int obj_desc_type = OD_OMIT_PREFIX | OD_NAME_ONLY;
274 floor_type *floor_ptr = creature_ptr->current_floor_ptr;
275 if (creature_ptr->cursed.has(TRC::CALL_ANIMAL) && one_in_(2500)) {
276 if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_ANIMAL, call_type)) {
277 GAME_TEXT o_name[MAX_NLEN];
278 describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC::CALL_ANIMAL), obj_desc_type);
279 msg_format(_("%sが動物を引き寄せた!", "Your %s has attracted an animal!"), o_name);
280 disturb(creature_ptr, false, true);
284 if (creature_ptr->cursed.has(TRC::CALL_DEMON) && one_in_(1111)) {
285 if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_DEMON, call_type)) {
286 GAME_TEXT o_name[MAX_NLEN];
287 describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC::CALL_DEMON), obj_desc_type);
288 msg_format(_("%sが悪魔を引き寄せた!", "Your %s has attracted a demon!"), o_name);
289 disturb(creature_ptr, false, true);
293 if (creature_ptr->cursed.has(TRC::CALL_DRAGON) && one_in_(800)) {
294 if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_DRAGON, call_type)) {
295 GAME_TEXT o_name[MAX_NLEN];
296 describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC::CALL_DRAGON), obj_desc_type);
297 msg_format(_("%sがドラゴンを引き寄せた!", "Your %s has attracted a dragon!"), o_name);
298 disturb(creature_ptr, false, true);
302 if (creature_ptr->cursed.has(TRC::CALL_UNDEAD) && one_in_(1111)) {
303 if (summon_specific(creature_ptr, 0, creature_ptr->y, creature_ptr->x, floor_ptr->dun_level, SUMMON_UNDEAD, call_type)) {
304 GAME_TEXT o_name[MAX_NLEN];
305 describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC::CALL_UNDEAD), obj_desc_type);
306 msg_format(_("%sが死霊を引き寄せた!", "Your %s has attracted an undead!"), o_name);
307 disturb(creature_ptr, false, true);
312 static void curse_cowardice(player_type *creature_ptr)
314 if ((creature_ptr->cursed.has_not(TRC::COWARDICE)) || !one_in_(1500))
317 if (has_resist_fear(creature_ptr))
320 disturb(creature_ptr, false, true);
321 msg_print(_("とても暗い... とても恐い!", "It's so dark... so scary!"));
322 set_afraid(creature_ptr, creature_ptr->afraid + 13 + randint1(26));
326 * @brief 装備による狂戦士化の発作を引き起こす
327 * @param creature_ptr プレイヤー情報への参照ポインタ
329 static void curse_berserk_rage(player_type *creature_ptr)
331 if ((creature_ptr->cursed.has_not(TRC::BERS_RAGE)) || !one_in_(1500))
334 disturb(creature_ptr, false, true);
335 msg_print(_("ウガァァア!", "RAAAAGHH!"));
336 msg_print(_("激怒の発作に襲われた!", "You feel a fit of rage coming over you!"));
337 (void)set_shero(creature_ptr, 10 + randint1(creature_ptr->lev), false);
338 (void)set_afraid(creature_ptr, 0);
341 static void curse_drain_hp(player_type *creature_ptr)
343 if ((creature_ptr->cursed.has_not(TRC::DRAIN_HP)) || !one_in_(666))
346 GAME_TEXT o_name[MAX_NLEN];
347 describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC::DRAIN_HP), (OD_OMIT_PREFIX | OD_NAME_ONLY));
348 msg_format(_("%sはあなたの体力を吸収した!", "Your %s drains HP from you!"), o_name);
349 take_hit(creature_ptr, DAMAGE_LOSELIFE, MIN(creature_ptr->lev * 2, 100), o_name);
352 static void curse_drain_mp(player_type *creature_ptr)
354 if ((creature_ptr->cursed.has_not(TRC::DRAIN_MANA)) || (creature_ptr->csp == 0) || !one_in_(666))
357 GAME_TEXT o_name[MAX_NLEN];
358 describe_flavor(creature_ptr, o_name, choose_cursed_obj_name(creature_ptr, TRC::DRAIN_MANA), (OD_OMIT_PREFIX | OD_NAME_ONLY));
359 msg_format(_("%sはあなたの魔力を吸収した!", "Your %s drains mana from you!"), o_name);
360 creature_ptr->csp -= MIN(creature_ptr->lev, 50);
361 if (creature_ptr->csp < 0) {
362 creature_ptr->csp = 0;
363 creature_ptr->csp_frac = 0;
366 creature_ptr->redraw |= PR_MANA;
369 static void occur_curse_effects(player_type *creature_ptr)
371 if ((creature_ptr->cursed.has_none_of(TRC_P_FLAG_MASK) && creature_ptr->cursed_special.has_none_of(TRCS_P_FLAG_MASK)) || creature_ptr->phase_out || creature_ptr->wild_mode)
374 curse_teleport(creature_ptr);
375 occur_chainsword_effect(creature_ptr);
376 if (creature_ptr->cursed.has(TRC::TY_CURSE) && one_in_(TY_CURSE_CHANCE)) {
378 (void)activate_ty_curse(creature_ptr, false, &count);
381 curse_drain_exp(creature_ptr);
382 multiply_low_curse(creature_ptr);
383 multiply_high_curse(creature_ptr);
384 curse_call_monster(creature_ptr);
385 curse_cowardice(creature_ptr);
386 curse_berserk_rage(creature_ptr);
387 if (creature_ptr->cursed.has(TRC::TELEPORT) && one_in_(200) && !creature_ptr->anti_tele) {
388 disturb(creature_ptr, false, true);
389 teleport_player(creature_ptr, 40, TELEPORT_PASSIVE);
392 curse_drain_hp(creature_ptr);
393 curse_drain_mp(creature_ptr);
397 * @brief 10ゲームターンが進行するごとに装備効果の発動判定を行う処理
398 * / Handle curse effects once every 10 game turns
399 * @param creature_ptr プレーヤーへの参照ポインタ
401 void execute_cursed_items_effect(player_type *creature_ptr)
403 occur_curse_effects(creature_ptr);
404 if (!one_in_(999) || creature_ptr->anti_magic || (one_in_(2) && has_resist_curse(creature_ptr)))
407 object_type *o_ptr = &creature_ptr->inventory_list[INVEN_LITE];
408 if (o_ptr->name1 != ART_JUDGE)
411 if (object_is_known(o_ptr))
412 msg_print(_("『審判の宝石』はあなたの体力を吸収した!", "The Jewel of Judgement drains life from you!"));
414 msg_print(_("なにかがあなたの体力を吸収した!", "Something drains life from you!"));
416 take_hit(creature_ptr, DAMAGE_LOSELIFE, MIN(creature_ptr->lev, 50), _("審判の宝石", "the Jewel of Judgement"));