OSDN Git Service

[Refactor] #1447 Replaced 'typedef struct grid_type grid_type;' to 'struct grid_type;'
[hengbandforosx/hengbandosx.git] / src / monster-attack / monster-eating.cpp
1 /*!
2  * @brief プレーヤーのHP/MP、アイテム、お金・明かりの残りターン、充填魔力を盗んだり減少させたりする処理
3  * @date 2020/05/31
4  * @author Hourier
5  */
6
7 #include "monster-attack/monster-eating.h"
8 #include "avatar/avatar.h"
9 #include "core/player-redraw-types.h"
10 #include "core/player-update-types.h"
11 #include "core/window-redrawer.h"
12 #include "flavor/flavor-describer.h"
13 #include "flavor/object-flavor-types.h"
14 #include "inventory/inventory-object.h"
15 #include "inventory/inventory-slot-types.h"
16 #include "mind/mind-mirror-master.h"
17 #include "monster-attack/monster-attack-util.h"
18 #include "monster/monster-status.h"
19 #include "object-hook/hook-enchant.h"
20 #include "object/object-info.h"
21 #include "object/object-kind.h"
22 #include "object/object-mark-types.h"
23 #include "player/digestion-processor.h"
24 #include "player/mimic-info-table.h"
25 #include "player/player-status-flags.h"
26 #include "player/player-status-table.h"
27 #include "status/experience.h"
28 #include "system/floor-type-definition.h"
29 #include "system/monster-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 "view/display-messages.h"
34 #include "world/world-object.h"
35
36 void process_eat_gold(player_type *target_ptr, monap_type *monap_ptr)
37 {
38     if (!target_ptr->paralyzed && (randint0(100) < (adj_dex_safe[target_ptr->stat_index[A_DEX]] + target_ptr->lev))) {
39         msg_print(_("しかし素早く財布を守った!", "You quickly protect your money pouch!"));
40         if (randint0(3))
41             monap_ptr->blinked = true;
42
43         return;
44     }
45
46     PRICE gold = (target_ptr->au / 10) + randint1(25);
47     if (gold < 2)
48         gold = 2;
49
50     if (gold > 5000)
51         gold = (target_ptr->au / 20) + randint1(3000);
52
53     if (gold > target_ptr->au)
54         gold = target_ptr->au;
55
56     target_ptr->au -= gold;
57     if (gold <= 0) {
58         msg_print(_("しかし何も盗まれなかった。", "Nothing was stolen."));
59     } else if (target_ptr->au > 0) {
60         msg_print(_("財布が軽くなった気がする。", "Your purse feels lighter."));
61         msg_format(_("$%ld のお金が盗まれた!", "%ld coins were stolen!"), (long)gold);
62         chg_virtue(target_ptr, V_SACRIFICE, 1);
63     } else {
64         msg_print(_("財布が軽くなった気がする。", "Your purse feels lighter."));
65         msg_print(_("お金が全部盗まれた!", "All of your coins were stolen!"));
66         chg_virtue(target_ptr, V_SACRIFICE, 2);
67     }
68
69     target_ptr->redraw |= (PR_GOLD);
70     target_ptr->window_flags |= (PW_PLAYER);
71     monap_ptr->blinked = true;
72 }
73
74 /*!
75  * @brief 盗み打撃の時にアイテムが盗まれるかどうかを判定する
76  * @param target_ptr プレーヤーへの参照ポインタ
77  * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
78  * @return 盗まれたらTRUE、何も盗まれなかったらFALSE
79  */
80 bool check_eat_item(player_type *target_ptr, monap_type *monap_ptr)
81 {
82     if (monster_confused_remaining(monap_ptr->m_ptr))
83         return false;
84
85     if (target_ptr->is_dead || check_multishadow(target_ptr))
86         return false;
87
88     if (!target_ptr->paralyzed && (randint0(100) < (adj_dex_safe[target_ptr->stat_index[A_DEX]] + target_ptr->lev))) {
89         msg_print(_("しかしあわててザックを取り返した!", "You grab hold of your backpack!"));
90         monap_ptr->blinked = true;
91         monap_ptr->obvious = true;
92         return false;
93     }
94
95     return true;
96 }
97
98 /*!
99  * @brief プレーヤーが持っているアイテムをモンスターに移す
100  * @param target_ptr プレーヤーへの参照ポインタ
101  * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
102  */
103 static void move_item_to_monster(player_type *target_ptr, monap_type *monap_ptr, const OBJECT_IDX o_idx)
104 {
105     if (o_idx == 0)
106         return;
107
108     object_type *j_ptr;
109     j_ptr = &target_ptr->current_floor_ptr->o_list[o_idx];
110     j_ptr->copy_from(monap_ptr->o_ptr);
111     j_ptr->number = 1;
112     if ((monap_ptr->o_ptr->tval == TV_ROD) || (monap_ptr->o_ptr->tval == TV_WAND)) {
113         j_ptr->pval = monap_ptr->o_ptr->pval / monap_ptr->o_ptr->number;
114         monap_ptr->o_ptr->pval -= j_ptr->pval;
115     }
116
117     j_ptr->marked = OM_TOUCHED;
118     j_ptr->held_m_idx = monap_ptr->m_idx;
119     monap_ptr->m_ptr->hold_o_idx_list.add(target_ptr->current_floor_ptr, o_idx);
120 }
121
122 /*!
123  * @brief アイテム盗み処理
124  * @param target_ptr プレーヤーへの参照ポインタ
125  * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
126  * @details eatとあるがお金や食べ物と違ってなくならない、盗んだモンスターを倒せば取り戻せる
127  */
128 void process_eat_item(player_type *target_ptr, monap_type *monap_ptr)
129 {
130     for (int i = 0; i < 10; i++) {
131         OBJECT_IDX o_idx;
132         INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
133         monap_ptr->o_ptr = &target_ptr->inventory_list[i_idx];
134         if (!monap_ptr->o_ptr->k_idx)
135             continue;
136
137         if (monap_ptr->o_ptr->is_artifact())
138             continue;
139
140         describe_flavor(target_ptr, monap_ptr->o_name, monap_ptr->o_ptr, OD_OMIT_PREFIX);
141 #ifdef JP
142         msg_format("%s(%c)を%s盗まれた!", monap_ptr->o_name, index_to_label(i_idx), ((monap_ptr->o_ptr->number > 1) ? "一つ" : ""));
143 #else
144         msg_format("%sour %s (%c) was stolen!", ((monap_ptr->o_ptr->number > 1) ? "One of y" : "Y"), monap_ptr->o_name, index_to_label(i_idx));
145 #endif
146         chg_virtue(target_ptr, V_SACRIFICE, 1);
147         o_idx = o_pop(target_ptr->current_floor_ptr);
148         move_item_to_monster(target_ptr, monap_ptr, o_idx);
149         inven_item_increase(target_ptr, i_idx, -1);
150         inven_item_optimize(target_ptr, i_idx);
151         monap_ptr->obvious = true;
152         monap_ptr->blinked = true;
153         break;
154     }
155 }
156
157 void process_eat_food(player_type *target_ptr, monap_type *monap_ptr)
158 {
159     for (int i = 0; i < 10; i++) {
160         INVENTORY_IDX i_idx = (INVENTORY_IDX)randint0(INVEN_PACK);
161         monap_ptr->o_ptr = &target_ptr->inventory_list[i_idx];
162         if (!monap_ptr->o_ptr->k_idx)
163             continue;
164
165         if ((monap_ptr->o_ptr->tval != TV_FOOD) && !((monap_ptr->o_ptr->tval == TV_CORPSE) && (monap_ptr->o_ptr->sval)))
166             continue;
167
168         describe_flavor(target_ptr, monap_ptr->o_name, monap_ptr->o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
169 #ifdef JP
170         msg_format("%s(%c)を%s食べられてしまった!", monap_ptr->o_name, index_to_label(i_idx), ((monap_ptr->o_ptr->number > 1) ? "一つ" : ""));
171 #else
172         msg_format("%sour %s (%c) was eaten!", ((monap_ptr->o_ptr->number > 1) ? "One of y" : "Y"), monap_ptr->o_name, index_to_label(i_idx));
173 #endif
174         inven_item_increase(target_ptr, i_idx, -1);
175         inven_item_optimize(target_ptr, i_idx);
176         monap_ptr->obvious = true;
177         break;
178     }
179 }
180
181 void process_eat_lite(player_type *target_ptr, monap_type *monap_ptr)
182 {
183     if ((monap_ptr->o_ptr->xtra4 <= 0) || monap_ptr->o_ptr->is_fixed_artifact())
184         return;
185
186     monap_ptr->o_ptr->xtra4 -= (int16_t)(250 + randint1(250));
187     if (monap_ptr->o_ptr->xtra4 < 1)
188         monap_ptr->o_ptr->xtra4 = 1;
189
190     if (!target_ptr->blind) {
191         msg_print(_("明かりが暗くなってしまった。", "Your light dims."));
192         monap_ptr->obvious = true;
193     }
194
195     target_ptr->window_flags |= (PW_EQUIP);
196 }
197
198 /*!
199  * @brief モンスターからの攻撃による充填魔力吸収処理
200  * @param target_ptr プレーヤーへの参照ポインタ
201  * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
202  * @return 吸収されたらTRUE、されなかったらFALSE
203  * @details 魔道具使用能力向上フラグがあれば、吸収量は全部ではない
204  * 詳細はOSDN #40911の議論を参照のこと
205  */
206 bool process_un_power(player_type *target_ptr, monap_type *monap_ptr)
207 {
208     if (((monap_ptr->o_ptr->tval != TV_STAFF) && (monap_ptr->o_ptr->tval != TV_WAND)) || (monap_ptr->o_ptr->pval == 0))
209         return false;
210
211     bool is_magic_mastery = has_magic_mastery(target_ptr) != 0;
212     object_kind *kind_ptr = &k_info[monap_ptr->o_ptr->k_idx];
213     PARAMETER_VALUE pval = kind_ptr->pval;
214     DEPTH level = monap_ptr->rlev;
215     HIT_POINT drain = is_magic_mastery ? MIN(pval, pval * level / 400 + pval * randint1(level) / 400) : pval;
216     if (drain <= 0)
217         return false;
218
219     msg_print(_("ザックからエネルギーが吸い取られた!", "Energy was drained from your pack!"));
220     if (is_magic_mastery)
221         msg_print(_("しかし、あなたの魔法を操る力がその一部を取り返した!", "However, your skill of magic mastery got back the part of energy!"));
222
223     monap_ptr->obvious = true;
224     HIT_POINT recovery = drain * kind_ptr->level;
225
226     if (monap_ptr->o_ptr->tval == TV_STAFF)
227         recovery *= monap_ptr->o_ptr->number;
228
229     recovery = MIN(recovery, monap_ptr->m_ptr->maxhp - monap_ptr->m_ptr->hp);
230     monap_ptr->m_ptr->hp += recovery;
231
232     if (target_ptr->health_who == monap_ptr->m_idx)
233         target_ptr->redraw |= PR_HEALTH;
234
235     if (target_ptr->riding == monap_ptr->m_idx)
236         target_ptr->redraw |= PR_UHEALTH;
237
238     monap_ptr->o_ptr->pval = !is_magic_mastery || (monap_ptr->o_ptr->pval == 1) ? 0 : monap_ptr->o_ptr->pval - drain;
239     target_ptr->update |= PU_COMBINE | PU_REORDER;
240     target_ptr->window_flags |= PW_INVEN;
241     return true;
242 }
243
244 bool check_drain_hp(player_type *target_ptr, const int32_t d)
245 {
246     bool resist_drain = !drain_exp(target_ptr, d, d / 10, 50);
247     if (target_ptr->mimic_form) {
248         return any_bits(mimic_info[target_ptr->mimic_form].choice, MIMIC_IS_NONLIVING) ? true : resist_drain;
249     }
250
251     switch (target_ptr->prace) {
252     case player_race_type::ZOMBIE:
253     case player_race_type::VAMPIRE:
254     case player_race_type::SPECTRE:
255     case player_race_type::SKELETON:
256     case player_race_type::BALROG:
257     case player_race_type::GOLEM:
258     case player_race_type::ANDROID:
259         return true;
260     default:
261         return resist_drain;
262     }
263 }
264
265 void process_drain_life(player_type *target_ptr, monap_type *monap_ptr, const bool resist_drain)
266 {
267     if ((monap_ptr->damage <= 5) || resist_drain)
268         return;
269
270     bool did_heal = monap_ptr->m_ptr->hp < monap_ptr->m_ptr->maxhp;
271     monap_ptr->m_ptr->hp += damroll(4, monap_ptr->damage / 6);
272     if (monap_ptr->m_ptr->hp > monap_ptr->m_ptr->maxhp)
273         monap_ptr->m_ptr->hp = monap_ptr->m_ptr->maxhp;
274
275     if (target_ptr->health_who == monap_ptr->m_idx)
276         target_ptr->redraw |= (PR_HEALTH);
277
278     if (target_ptr->riding == monap_ptr->m_idx)
279         target_ptr->redraw |= (PR_UHEALTH);
280
281     if (monap_ptr->m_ptr->ml && did_heal)
282         msg_format(_("%sは体力を回復したようだ。", "%^s appears healthier."), monap_ptr->m_name);
283 }
284
285 void process_drain_mana(player_type *target_ptr, monap_type *monap_ptr)
286 {
287     if (check_multishadow(target_ptr)) {
288         msg_print(_("攻撃は幻影に命中し、あなたには届かなかった。", "The attack hits Shadow, but you are unharmed!"));
289         return;
290     }
291
292     monap_ptr->do_cut = 0;
293     target_ptr->csp -= monap_ptr->damage;
294     if (target_ptr->csp < 0) {
295         target_ptr->csp = 0;
296         target_ptr->csp_frac = 0;
297     }
298
299     target_ptr->redraw |= (PR_MANA);
300 }
301
302 /*!
303  * @brief モンスターからの空腹進行処理
304  * @param target_ptr プレーヤーへの参照ポインタ
305  * @monap_ptr モンスターからモンスターへの直接攻撃構造体への参照ポインタ
306  * @details 空腹、衰弱の一歩手前で止める優しさは残す。
307  */
308 void process_monster_attack_hungry(player_type *target_ptr, monap_type *monap_ptr)
309 {
310     msg_format(_("あなたは腹が減った!", "You feel hungry!"));
311     auto subtracted_food = static_cast<int16_t>(target_ptr->food - monap_ptr->damage);
312     if ((target_ptr->food >= PY_FOOD_ALERT) && (PY_FOOD_ALERT > subtracted_food)) {
313         set_food(target_ptr, PY_FOOD_ALERT - 1);
314     } else if ((target_ptr->food > PY_FOOD_FAINT) && (PY_FOOD_FAINT >= subtracted_food)) {
315         set_food(target_ptr, PY_FOOD_FAINT);
316     } else {
317         set_food(target_ptr, subtracted_food);
318     }
319 }