OSDN Git Service

[Refactor] #37353 アイテム条件処理を object-hook.c/h へ分離。
[hengband/hengband.git] / src / cmd-eat.c
1 /*!\r
2  * @file cmd-eat.c\r
3  * @brief プレイヤーの食べるコマンド実装\r
4  * @date 2018/09/07\r
5  * @details\r
6  * cmd6.cより分離。\r
7  */\r
8 \r
9 \r
10 #include "angband.h"\r
11 #include "object-hook.h"\r
12 \r
13 /*!\r
14  * @brief 食料を食べるコマンドのサブルーチン\r
15  * @param item 食べるオブジェクトの所持品ID\r
16  * @return なし\r
17  */\r
18 void do_cmd_eat_food_aux(int item)\r
19 {\r
20         int ident, lev;\r
21         object_type *o_ptr;\r
22 \r
23         if (music_singing_any()) stop_singing();\r
24         if (hex_spelling_any()) stop_hex_spell_all();\r
25 \r
26         /* Get the item (in the pack) */\r
27         if (item >= 0)\r
28         {\r
29                 o_ptr = &inventory[item];\r
30         }\r
31 \r
32         /* Get the item (on the floor) */\r
33         else\r
34         {\r
35                 o_ptr = &o_list[0 - item];\r
36         }\r
37 \r
38         /* Sound */\r
39         sound(SOUND_EAT);\r
40 \r
41         /* Take a turn */\r
42         p_ptr->energy_use = 100;\r
43 \r
44         /* Identity not known yet */\r
45         ident = FALSE;\r
46 \r
47         /* Object level */\r
48         lev = k_info[o_ptr->k_idx].level;\r
49 \r
50         if (o_ptr->tval == TV_FOOD)\r
51         {\r
52                 /* Analyze the food */\r
53                 switch (o_ptr->sval)\r
54                 {\r
55                 case SV_FOOD_POISON:\r
56                 {\r
57                         if (!(p_ptr->resist_pois || IS_OPPOSE_POIS()))\r
58                         {\r
59                                 if (set_poisoned(p_ptr->poisoned + randint0(10) + 10))\r
60                                 {\r
61                                         ident = TRUE;\r
62                                 }\r
63                         }\r
64                         break;\r
65                 }\r
66 \r
67                 case SV_FOOD_BLINDNESS:\r
68                 {\r
69                         if (!p_ptr->resist_blind)\r
70                         {\r
71                                 if (set_blind(p_ptr->blind + randint0(200) + 200))\r
72                                 {\r
73                                         ident = TRUE;\r
74                                 }\r
75                         }\r
76                         break;\r
77                 }\r
78 \r
79                 case SV_FOOD_PARANOIA:\r
80                 {\r
81                         if (!p_ptr->resist_fear)\r
82                         {\r
83                                 if (set_afraid(p_ptr->afraid + randint0(10) + 10))\r
84                                 {\r
85                                         ident = TRUE;\r
86                                 }\r
87                         }\r
88                         break;\r
89                 }\r
90 \r
91                 case SV_FOOD_CONFUSION:\r
92                 {\r
93                         if (!p_ptr->resist_conf)\r
94                         {\r
95                                 if (set_confused(p_ptr->confused + randint0(10) + 10))\r
96                                 {\r
97                                         ident = TRUE;\r
98                                 }\r
99                         }\r
100                         break;\r
101                 }\r
102 \r
103                 case SV_FOOD_HALLUCINATION:\r
104                 {\r
105                         if (!p_ptr->resist_chaos)\r
106                         {\r
107                                 if (set_image(p_ptr->image + randint0(250) + 250))\r
108                                 {\r
109                                         ident = TRUE;\r
110                                 }\r
111                         }\r
112                         break;\r
113                 }\r
114 \r
115                 case SV_FOOD_PARALYSIS:\r
116                 {\r
117                         if (!p_ptr->free_act)\r
118                         {\r
119                                 if (set_paralyzed(p_ptr->paralyzed + randint0(10) + 10))\r
120                                 {\r
121                                         ident = TRUE;\r
122                                 }\r
123                         }\r
124                         break;\r
125                 }\r
126 \r
127                 case SV_FOOD_WEAKNESS:\r
128                 {\r
129                         take_hit(DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);\r
130                         (void)do_dec_stat(A_STR);\r
131                         ident = TRUE;\r
132                         break;\r
133                 }\r
134 \r
135                 case SV_FOOD_SICKNESS:\r
136                 {\r
137                         take_hit(DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);\r
138                         (void)do_dec_stat(A_CON);\r
139                         ident = TRUE;\r
140                         break;\r
141                 }\r
142 \r
143                 case SV_FOOD_STUPIDITY:\r
144                 {\r
145                         take_hit(DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);\r
146                         (void)do_dec_stat(A_INT);\r
147                         ident = TRUE;\r
148                         break;\r
149                 }\r
150 \r
151                 case SV_FOOD_NAIVETY:\r
152                 {\r
153                         take_hit(DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);\r
154                         (void)do_dec_stat(A_WIS);\r
155                         ident = TRUE;\r
156                         break;\r
157                 }\r
158 \r
159                 case SV_FOOD_UNHEALTH:\r
160                 {\r
161                         take_hit(DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);\r
162                         (void)do_dec_stat(A_CON);\r
163                         ident = TRUE;\r
164                         break;\r
165                 }\r
166 \r
167                 case SV_FOOD_DISEASE:\r
168                 {\r
169                         take_hit(DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);\r
170                         (void)do_dec_stat(A_STR);\r
171                         ident = TRUE;\r
172                         break;\r
173                 }\r
174 \r
175                 case SV_FOOD_CURE_POISON:\r
176                 {\r
177                         if (set_poisoned(0)) ident = TRUE;\r
178                         break;\r
179                 }\r
180 \r
181                 case SV_FOOD_CURE_BLINDNESS:\r
182                 {\r
183                         if (set_blind(0)) ident = TRUE;\r
184                         break;\r
185                 }\r
186 \r
187                 case SV_FOOD_CURE_PARANOIA:\r
188                 {\r
189                         if (set_afraid(0)) ident = TRUE;\r
190                         break;\r
191                 }\r
192 \r
193                 case SV_FOOD_CURE_CONFUSION:\r
194                 {\r
195                         if (set_confused(0)) ident = TRUE;\r
196                         break;\r
197                 }\r
198 \r
199                 case SV_FOOD_CURE_SERIOUS:\r
200                 {\r
201                         if (hp_player(damroll(4, 8))) ident = TRUE;\r
202                         break;\r
203                 }\r
204 \r
205                 case SV_FOOD_RESTORE_STR:\r
206                 {\r
207                         if (do_res_stat(A_STR)) ident = TRUE;\r
208                         break;\r
209                 }\r
210 \r
211                 case SV_FOOD_RESTORE_CON:\r
212                 {\r
213                         if (do_res_stat(A_CON)) ident = TRUE;\r
214                         break;\r
215                 }\r
216 \r
217                 case SV_FOOD_RESTORING:\r
218                 {\r
219                         if (do_res_stat(A_STR)) ident = TRUE;\r
220                         if (do_res_stat(A_INT)) ident = TRUE;\r
221                         if (do_res_stat(A_WIS)) ident = TRUE;\r
222                         if (do_res_stat(A_DEX)) ident = TRUE;\r
223                         if (do_res_stat(A_CON)) ident = TRUE;\r
224                         if (do_res_stat(A_CHR)) ident = TRUE;\r
225                         break;\r
226                 }\r
227 \r
228 \r
229 #ifdef JP\r
230                 /* それぞれの食べ物の感想をオリジナルより細かく表現 */\r
231                 case SV_FOOD_BISCUIT:\r
232                 {\r
233                         msg_print("甘くてサクサクしてとてもおいしい。");\r
234                         ident = TRUE;\r
235                         break;\r
236                 }\r
237 \r
238                 case SV_FOOD_JERKY:\r
239                 {\r
240                         msg_print("歯ごたえがあっておいしい。");\r
241                         ident = TRUE;\r
242                         break;\r
243                 }\r
244 \r
245                 case SV_FOOD_SLIME_MOLD:\r
246                 {\r
247                         msg_print("これはなんとも形容しがたい味だ。");\r
248                         ident = TRUE;\r
249                         break;\r
250                 }\r
251 \r
252                 case SV_FOOD_RATION:\r
253                 {\r
254                         msg_print("これはおいしい。");\r
255                         ident = TRUE;\r
256                         break;\r
257                 }\r
258 #else\r
259                 case SV_FOOD_RATION:\r
260                 case SV_FOOD_BISCUIT:\r
261                 case SV_FOOD_JERKY:\r
262                 case SV_FOOD_SLIME_MOLD:\r
263                 {\r
264                         msg_print("That tastes good.");\r
265                         ident = TRUE;\r
266                         break;\r
267                 }\r
268 #endif\r
269 \r
270 \r
271                 case SV_FOOD_WAYBREAD:\r
272                 {\r
273                         msg_print(_("これはひじょうに美味だ。", "That tastes good."));\r
274                         (void)set_poisoned(0);\r
275                         (void)hp_player(damroll(4, 8));\r
276                         ident = TRUE;\r
277                         break;\r
278                 }\r
279 \r
280 #ifdef JP\r
281                 case SV_FOOD_PINT_OF_ALE:\r
282                 {\r
283                         msg_print("のどごし爽やかだ。");\r
284                         ident = TRUE;\r
285                         break;\r
286                 }\r
287 \r
288                 case SV_FOOD_PINT_OF_WINE:\r
289                 {\r
290                         msg_print("That tastes good.");\r
291                         ident = TRUE;\r
292                         break;\r
293                 }\r
294 #else\r
295                 case SV_FOOD_PINT_OF_ALE:\r
296                 case SV_FOOD_PINT_OF_WINE:\r
297                 {\r
298                         msg_print("That tastes good.");\r
299                         ident = TRUE;\r
300                         break;\r
301                 }\r
302 #endif\r
303 \r
304                 }\r
305         }\r
306 \r
307         /* Combine / Reorder the pack (later) */\r
308         p_ptr->notice |= (PN_COMBINE | PN_REORDER);\r
309 \r
310         if (!(object_is_aware(o_ptr)))\r
311         {\r
312                 chg_virtue(V_KNOWLEDGE, -1);\r
313                 chg_virtue(V_PATIENCE, -1);\r
314                 chg_virtue(V_CHANCE, 1);\r
315         }\r
316 \r
317         /* We have tried it */\r
318         if (o_ptr->tval == TV_FOOD) object_tried(o_ptr);\r
319 \r
320         /* The player is now aware of the object */\r
321         if (ident && !object_is_aware(o_ptr))\r
322         {\r
323                 object_aware(o_ptr);\r
324                 gain_exp((lev + (p_ptr->lev >> 1)) / p_ptr->lev);\r
325         }\r
326 \r
327         /* Window stuff */\r
328         p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);\r
329 \r
330 \r
331         /* Food can feed the player */\r
332         if (prace_is_(RACE_VAMPIRE) || (p_ptr->mimic_form == MIMIC_VAMPIRE))\r
333         {\r
334                 /* Reduced nutritional benefit */\r
335                 (void)set_food(p_ptr->food + (o_ptr->pval / 10));\r
336                 msg_print(_("あなたのような者にとって食糧など僅かな栄養にしかならない。",\r
337                         "Mere victuals hold scant sustenance for a being such as yourself."));\r
338 \r
339                 if (p_ptr->food < PY_FOOD_ALERT)   /* Hungry */\r
340                         msg_print(_("あなたの飢えは新鮮な血によってのみ満たされる!",\r
341                                 "Your hunger can only be satisfied with fresh blood!"));\r
342         }\r
343         else if ((prace_is_(RACE_SKELETON) ||\r
344                 prace_is_(RACE_GOLEM) ||\r
345                 prace_is_(RACE_ZOMBIE) ||\r
346                 prace_is_(RACE_SPECTRE)) &&\r
347                 (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND))\r
348         {\r
349                 cptr staff;\r
350 \r
351                 if (o_ptr->tval == TV_STAFF &&\r
352                         (item < 0) && (o_ptr->number > 1))\r
353                 {\r
354                         msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));\r
355                         return;\r
356                 }\r
357                 staff = (o_ptr->tval == TV_STAFF) ? _("杖", "staff") : _("魔法棒", "wand");\r
358 \r
359                 /* "Eat" charges */\r
360                 if (o_ptr->pval == 0)\r
361                 {\r
362                         msg_format(_("この%sにはもう魔力が残っていない。", "The %s has no charges left."), staff);\r
363                         o_ptr->ident |= (IDENT_EMPTY);\r
364 \r
365                         /* Combine / Reorder the pack (later) */\r
366                         p_ptr->notice |= (PN_COMBINE | PN_REORDER);\r
367                         p_ptr->window |= (PW_INVEN);\r
368 \r
369                         return;\r
370                 }\r
371                 msg_format(_("あなたは%sの魔力をエネルギー源として吸収した。", "You absorb mana of the %s as your energy."), staff);\r
372 \r
373                 /* Use a single charge */\r
374                 o_ptr->pval--;\r
375 \r
376                 /* Eat a charge */\r
377                 set_food(p_ptr->food + 5000);\r
378 \r
379                 /* XXX Hack -- unstack if necessary */\r
380                 if (o_ptr->tval == TV_STAFF &&\r
381                         (item >= 0) && (o_ptr->number > 1))\r
382                 {\r
383                         object_type forge;\r
384                         object_type *q_ptr;\r
385 \r
386                         /* Get local object */\r
387                         q_ptr = &forge;\r
388 \r
389                         /* Obtain a local object */\r
390                         object_copy(q_ptr, o_ptr);\r
391 \r
392                         /* Modify quantity */\r
393                         q_ptr->number = 1;\r
394 \r
395                         /* Restore the charges */\r
396                         o_ptr->pval++;\r
397 \r
398                         /* Unstack the used item */\r
399                         o_ptr->number--;\r
400                         p_ptr->total_weight -= q_ptr->weight;\r
401                         item = inven_carry(q_ptr);\r
402 \r
403                         /* Message */\r
404                         msg_format(_("杖をまとめなおした。", "You unstack your staff."));\r
405                 }\r
406 \r
407                 /* Describe charges in the pack */\r
408                 if (item >= 0)\r
409                 {\r
410                         inven_item_charges(item);\r
411                 }\r
412 \r
413                 /* Describe charges on the floor */\r
414                 else\r
415                 {\r
416                         floor_item_charges(0 - item);\r
417                 }\r
418 \r
419                 /* Window stuff */\r
420                 p_ptr->window |= (PW_INVEN | PW_EQUIP);\r
421 \r
422                 /* Don't eat a staff/wand itself */\r
423                 return;\r
424         }\r
425         else if ((prace_is_(RACE_DEMON) ||\r
426                 (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_DEMON)) &&\r
427                 (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_CORPSE &&\r
428                         my_strchr("pht", r_info[o_ptr->pval].d_char)))\r
429         {\r
430                 /* Drain vitality of humanoids */\r
431                 char o_name[MAX_NLEN];\r
432                 object_desc(o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));\r
433                 msg_format(_("%sは燃え上り灰になった。精力を吸収した気がする。", "%^s is burnt to ashes.  You absorb its vitality!"), o_name);\r
434                 (void)set_food(PY_FOOD_MAX - 1);\r
435         }\r
436         else if (prace_is_(RACE_SKELETON))\r
437         {\r
438 #if 0\r
439                 if (o_ptr->tval == TV_SKELETON ||\r
440                         (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_SKELETON))\r
441                 {\r
442                         msg_print(_("あなたは骨で自分の体を補った。", "Your body absorbs the bone."));\r
443                         set_food(p_ptr->food + 5000);\r
444                 }\r
445                 else\r
446 #endif\r
447 \r
448                         if (!((o_ptr->sval == SV_FOOD_WAYBREAD) ||\r
449                                 (o_ptr->sval < SV_FOOD_BISCUIT)))\r
450                         {\r
451                                 object_type forge;\r
452                                 object_type *q_ptr = &forge;\r
453 \r
454                                 msg_print(_("食べ物がアゴを素通りして落ちた!", "The food falls through your jaws!"));\r
455 \r
456                                 /* Create the item */\r
457                                 object_prep(q_ptr, lookup_kind(o_ptr->tval, o_ptr->sval));\r
458 \r
459                                 /* Drop the object from heaven */\r
460                                 (void)drop_near(q_ptr, -1, p_ptr->y, p_ptr->x);\r
461                         }\r
462                         else\r
463                         {\r
464                                 msg_print(_("食べ物がアゴを素通りして落ち、消えた!", "The food falls through your jaws and vanishes!"));\r
465                         }\r
466         }\r
467         else if (prace_is_(RACE_GOLEM) ||\r
468                 prace_is_(RACE_ZOMBIE) ||\r
469                 prace_is_(RACE_ENT) ||\r
470                 prace_is_(RACE_DEMON) ||\r
471                 prace_is_(RACE_ANDROID) ||\r
472                 prace_is_(RACE_SPECTRE) ||\r
473                 (mimic_info[p_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_NONLIVING))\r
474         {\r
475                 msg_print(_("生者の食物はあなたにとってほとんど栄養にならない。", "The food of mortals is poor sustenance for you."));\r
476                 set_food(p_ptr->food + ((o_ptr->pval) / 20));\r
477         }\r
478         else if (o_ptr->tval == TV_FOOD && o_ptr->sval == SV_FOOD_WAYBREAD)\r
479         {\r
480                 /* Waybread is always fully satisfying. */\r
481                 set_food(MAX(p_ptr->food, PY_FOOD_MAX - 1));\r
482         }\r
483         else\r
484         {\r
485                 /* Food can feed the player */\r
486                 (void)set_food(p_ptr->food + o_ptr->pval);\r
487         }\r
488 \r
489         /* Destroy a food in the pack */\r
490         if (item >= 0)\r
491         {\r
492                 inven_item_increase(item, -1);\r
493                 inven_item_describe(item);\r
494                 inven_item_optimize(item);\r
495         }\r
496 \r
497         /* Destroy a food on the floor */\r
498         else\r
499         {\r
500                 floor_item_increase(0 - item, -1);\r
501                 floor_item_describe(0 - item);\r
502                 floor_item_optimize(0 - item);\r
503         }\r
504 }\r
505 \r
506 \r
507 /*!\r
508  * @brief 食料を食べるコマンドのメインルーチン /\r
509  * Eat some food (from the pack or floor)\r
510  * @return なし\r
511  */\r
512 void do_cmd_eat_food(void)\r
513 {\r
514         OBJECT_IDX item;\r
515         cptr        q, s;\r
516 \r
517 \r
518         if (p_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN))\r
519         {\r
520                 set_action(ACTION_NONE);\r
521         }\r
522 \r
523         /* Restrict choices to food */\r
524         item_tester_hook = item_tester_hook_eatable;\r
525 \r
526         /* Get an item */\r
527         q = _("どれを食べますか? ", "Eat which item? ");\r
528         s = _("食べ物がない。", "You have nothing to eat.");\r
529 \r
530         if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;\r
531 \r
532         /* Eat the object */\r
533         do_cmd_eat_food_aux(item);\r
534 }\r
535 \r