OSDN Git Service

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