2 * @brief プレイヤーのHP/MP、アイテム、お金・明かりの残りターン、充填魔力を盗んだり減少させたりする処理
7 #include "monster-attack/monster-eating.h"
8 #include "avatar/avatar.h"
9 #include "core/player-redraw-types.h"
10 #include "core/window-redrawer.h"
11 #include "flavor/flavor-describer.h"
12 #include "flavor/object-flavor-types.h"
13 #include "inventory/inventory-object.h"
14 #include "inventory/inventory-slot-types.h"
15 #include "mind/mind-mirror-master.h"
16 #include "monster-attack/monster-attack-player.h"
17 #include "monster/monster-status.h"
18 #include "object/object-info.h"
19 #include "object/object-mark-types.h"
20 #include "player-base/player-race.h"
21 #include "player-info/race-info.h"
22 #include "player/digestion-processor.h"
23 #include "player/player-status-flags.h"
24 #include "player/player-status-table.h"
25 #include "status/experience.h"
26 #include "system/baseitem-info.h"
27 #include "system/floor-type-definition.h"
28 #include "system/item-entity.h"
29 #include "system/monster-entity.h"
30 #include "system/player-type-definition.h"
31 #include "system/redrawing-flags-updater.h"
32 #include "timed-effect/player-blindness.h"
33 #include "timed-effect/player-paralysis.h"
34 #include "timed-effect/timed-effects.h"
35 #include "util/bit-flags-calculator.h"
36 #include "view/display-messages.h"
37 #include "world/world-object.h"
39 void process_eat_gold(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
41 auto is_paralyzed = player_ptr->effects()->paralysis()->is_paralyzed();
42 if (!is_paralyzed && (randint0(100) < (adj_dex_safe[player_ptr->stat_index[A_DEX]] + player_ptr->lev))) {
43 msg_print(_("しかし素早く財布を守った!", "You quickly protect your money pouch!"));
45 monap_ptr->blinked = true;
51 PRICE gold = (player_ptr->au / 10) + randint1(25);
57 gold = (player_ptr->au / 20) + randint1(3000);
60 if (gold > player_ptr->au) {
61 gold = player_ptr->au;
64 player_ptr->au -= gold;
66 msg_print(_("しかし何も盗まれなかった。", "Nothing was stolen."));
67 } else if (player_ptr->au > 0) {
68 msg_print(_("財布が軽くなった気がする。", "Your purse feels lighter."));
69 msg_format(_("$%ld のお金が盗まれた!", "%ld coins were stolen!"), (long)gold);
70 chg_virtue(player_ptr, Virtue::SACRIFICE, 1);
72 msg_print(_("財布が軽くなった気がする。", "Your purse feels lighter."));
73 msg_print(_("お金が全部盗まれた!", "All of your coins were stolen!"));
74 chg_virtue(player_ptr, Virtue::SACRIFICE, 2);
77 auto &rfu = RedrawingFlagsUpdater::get_instance();
78 rfu.set_flag(MainWindowRedrawingFlag::GOLD);
79 player_ptr->window_flags |= (PW_PLAYER);
80 monap_ptr->blinked = true;
84 * @brief 盗み打撃の時にアイテムが盗まれるかどうかを判定する
85 * @param player_ptr プレイヤーへの参照ポインタ
86 * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
87 * @return 盗まれたらTRUE、何も盗まれなかったらFALSE
89 bool check_eat_item(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
91 if (monap_ptr->m_ptr->is_confused()) {
95 if (player_ptr->is_dead || check_multishadow(player_ptr)) {
99 auto is_paralyzed = player_ptr->effects()->paralysis()->is_paralyzed();
100 if (!is_paralyzed && (randint0(100) < (adj_dex_safe[player_ptr->stat_index[A_DEX]] + player_ptr->lev))) {
101 msg_print(_("しかしあわててザックを取り返した!", "You grab hold of your backpack!"));
102 monap_ptr->blinked = true;
103 monap_ptr->obvious = true;
111 * @brief プレイヤーが持っているアイテムをモンスターに移す
112 * @param player_ptr プレイヤーへの参照ポインタ
113 * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
115 static void move_item_to_monster(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr, const OBJECT_IDX o_idx)
121 auto *j_ptr = &player_ptr->current_floor_ptr->o_list[o_idx];
122 j_ptr->copy_from(monap_ptr->o_ptr);
124 if (monap_ptr->o_ptr->is_wand_rod()) {
125 j_ptr->pval = monap_ptr->o_ptr->pval / monap_ptr->o_ptr->number;
126 monap_ptr->o_ptr->pval -= j_ptr->pval;
129 j_ptr->marked.clear().set(OmType::TOUCHED);
130 j_ptr->held_m_idx = monap_ptr->m_idx;
131 monap_ptr->m_ptr->hold_o_idx_list.add(player_ptr->current_floor_ptr, o_idx);
136 * @param player_ptr プレイヤーへの参照ポインタ
137 * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
138 * @details eatとあるがお金や食べ物と違ってなくならない、盗んだモンスターを倒せば取り戻せる
140 void process_eat_item(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
142 for (int i = 0; i < 10; i++) {
144 INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
145 monap_ptr->o_ptr = &player_ptr->inventory_list[i_idx];
146 if (!monap_ptr->o_ptr->is_valid()) {
150 if (monap_ptr->o_ptr->is_fixed_or_random_artifact()) {
154 const auto item_name = describe_flavor(player_ptr, monap_ptr->o_ptr, OD_OMIT_PREFIX);
156 msg_format("%s(%c)を%s盗まれた!", item_name.data(), index_to_label(i_idx), ((monap_ptr->o_ptr->number > 1) ? "一つ" : ""));
158 msg_format("%sour %s (%c) was stolen!", ((monap_ptr->o_ptr->number > 1) ? "One of y" : "Y"), item_name.data(), index_to_label(i_idx));
160 chg_virtue(player_ptr, Virtue::SACRIFICE, 1);
161 o_idx = o_pop(player_ptr->current_floor_ptr);
162 move_item_to_monster(player_ptr, monap_ptr, o_idx);
163 inven_item_increase(player_ptr, i_idx, -1);
164 inven_item_optimize(player_ptr, i_idx);
165 monap_ptr->obvious = true;
166 monap_ptr->blinked = true;
171 void process_eat_food(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
173 for (int i = 0; i < 10; i++) {
174 INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
175 monap_ptr->o_ptr = &player_ptr->inventory_list[i_idx];
176 if (!monap_ptr->o_ptr->is_valid()) {
180 const auto tval = monap_ptr->o_ptr->bi_key.tval();
181 if ((tval != ItemKindType::FOOD) && !((tval == ItemKindType::CORPSE) && (monap_ptr->o_ptr->bi_key.sval() != 0))) {
185 const auto item_name = describe_flavor(player_ptr, monap_ptr->o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
187 msg_format("%s(%c)を%s食べられてしまった!", item_name.data(), index_to_label(i_idx), ((monap_ptr->o_ptr->number > 1) ? "一つ" : ""));
189 msg_format("%sour %s (%c) was eaten!", ((monap_ptr->o_ptr->number > 1) ? "One of y" : "Y"), item_name.data(), index_to_label(i_idx));
191 inven_item_increase(player_ptr, i_idx, -1);
192 inven_item_optimize(player_ptr, i_idx);
193 monap_ptr->obvious = true;
198 void process_eat_lite(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
200 if ((monap_ptr->o_ptr->fuel <= 0) || monap_ptr->o_ptr->is_fixed_artifact()) {
204 monap_ptr->o_ptr->fuel -= 250 + randint1(250);
205 if (monap_ptr->o_ptr->fuel < 1) {
206 monap_ptr->o_ptr->fuel = 1;
209 if (!player_ptr->effects()->blindness()->is_blind()) {
210 msg_print(_("明かりが暗くなってしまった。", "Your light dims."));
211 monap_ptr->obvious = true;
214 player_ptr->window_flags |= (PW_EQUIPMENT);
218 * @brief モンスターからの攻撃による充填魔力吸収処理
219 * @param player_ptr プレイヤーへの参照ポインタ
220 * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
221 * @return 吸収されたらTRUE、されなかったらFALSE
222 * @details 魔道具使用能力向上フラグがあれば、吸収量は全部ではない
223 * 詳細はOSDN #40911の議論を参照のこと
225 bool process_un_power(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
227 if (!monap_ptr->o_ptr->is_wand_staff() || (monap_ptr->o_ptr->pval == 0)) {
231 const auto is_magic_mastery = has_magic_mastery(player_ptr) != 0;
232 const auto &baseitem = monap_ptr->o_ptr->get_baseitem();
233 const auto pval = baseitem.pval;
234 const auto level = monap_ptr->rlev;
235 auto drain = is_magic_mastery ? std::min<short>(pval, pval * level / 400 + pval * randint1(level) / 400) : pval;
236 drain = std::min(drain, monap_ptr->o_ptr->pval);
241 msg_print(_("ザックからエネルギーが吸い取られた!", "Energy was drained from your pack!"));
242 if (is_magic_mastery && (drain != monap_ptr->o_ptr->pval)) {
243 msg_print(_("しかし、あなたの魔法を操る力がその一部を取り返した!", "However, your skill of magic mastery got back the part of energy!"));
246 monap_ptr->obvious = true;
247 auto recovery = drain * baseitem.level;
248 const auto tval = monap_ptr->o_ptr->bi_key.tval();
249 if (tval == ItemKindType::STAFF) {
250 recovery *= monap_ptr->o_ptr->number;
253 recovery = std::min(recovery, monap_ptr->m_ptr->maxhp - monap_ptr->m_ptr->hp);
254 monap_ptr->m_ptr->hp += recovery;
256 auto &rfu = RedrawingFlagsUpdater::get_instance();
257 if (player_ptr->health_who == monap_ptr->m_idx) {
258 rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
261 if (player_ptr->riding == monap_ptr->m_idx) {
262 rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
265 monap_ptr->o_ptr->pval = !is_magic_mastery || (monap_ptr->o_ptr->pval == 1) ? 0 : monap_ptr->o_ptr->pval - drain;
267 StatusRedrawingFlag::COMBINATION,
268 StatusRedrawingFlag::REORDER,
270 rfu.set_flags(flags);
271 player_ptr->window_flags |= PW_INVENTORY;
275 bool check_drain_hp(PlayerType *player_ptr, const int32_t d)
277 bool resist_drain = !drain_exp(player_ptr, d, d / 10, 50);
278 if (player_ptr->mimic_form != MimicKindType::NONE) {
279 return PlayerRace(player_ptr).is_mimic_nonliving() ? true : resist_drain;
282 switch (player_ptr->prace) {
283 case PlayerRaceType::ZOMBIE:
284 case PlayerRaceType::VAMPIRE:
285 case PlayerRaceType::SPECTRE:
286 case PlayerRaceType::SKELETON:
287 case PlayerRaceType::BALROG:
288 case PlayerRaceType::GOLEM:
289 case PlayerRaceType::ANDROID:
296 void process_drain_life(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr, const bool resist_drain)
298 if ((monap_ptr->damage <= 5) || resist_drain) {
302 bool did_heal = monap_ptr->m_ptr->hp < monap_ptr->m_ptr->maxhp;
303 monap_ptr->m_ptr->hp += damroll(4, monap_ptr->damage / 6);
304 if (monap_ptr->m_ptr->hp > monap_ptr->m_ptr->maxhp) {
305 monap_ptr->m_ptr->hp = monap_ptr->m_ptr->maxhp;
308 auto &rfu = RedrawingFlagsUpdater::get_instance();
309 if (player_ptr->health_who == monap_ptr->m_idx) {
310 rfu.set_flag(MainWindowRedrawingFlag::HEALTH);
313 if (player_ptr->riding == monap_ptr->m_idx) {
314 rfu.set_flag(MainWindowRedrawingFlag::UHEALTH);
317 if (monap_ptr->m_ptr->ml && did_heal) {
318 msg_format(_("%sは体力を回復したようだ。", "%s^ appears healthier."), monap_ptr->m_name);
322 void process_drain_mana(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
324 if (check_multishadow(player_ptr)) {
325 msg_print(_("攻撃は幻影に命中し、あなたには届かなかった。", "The attack hits Shadow, but you are unharmed!"));
329 monap_ptr->do_cut = 0;
330 player_ptr->csp -= monap_ptr->damage;
331 if (player_ptr->csp < 0) {
333 player_ptr->csp_frac = 0;
336 RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::MP);
340 * @brief モンスターからの空腹進行処理
341 * @param player_ptr プレイヤーへの参照ポインタ
342 * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
343 * @details 空腹、衰弱の一歩手前で止める優しさは残す。
345 void process_monster_attack_hungry(PlayerType *player_ptr, MonsterAttackPlayer *monap_ptr)
347 msg_format(_("あなたは腹が減った!", "You feel hungry!"));
348 auto subtracted_food = static_cast<int16_t>(player_ptr->food - monap_ptr->damage);
349 if ((player_ptr->food >= PY_FOOD_ALERT) && (PY_FOOD_ALERT > subtracted_food)) {
350 set_food(player_ptr, PY_FOOD_ALERT - 1);
351 } else if ((player_ptr->food > PY_FOOD_FAINT) && (PY_FOOD_FAINT >= subtracted_food)) {
352 set_food(player_ptr, PY_FOOD_FAINT);
354 set_food(player_ptr, subtracted_food);