OSDN Git Service

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