OSDN Git Service

[Refactor] #40514 player_type の resist_chaos, resist_dark 変数を廃止. / Abolished the...
[hengband/hengband.git] / src / cmd-item / cmd-eat.c
1 /*!
2  * @brief プレイヤーの食べるコマンド実装
3  * @date 2018/09/07
4  @ @author deskull
5  */
6
7 #include "cmd-item/cmd-eat.h"
8 #include "core/hp-mp-processor.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 "floor/floor-object.h"
14 #include "inventory/inventory-object.h"
15 #include "main/sound-definitions-table.h"
16 #include "main/sound-of-music.h"
17 #include "monster-race/monster-race.h"
18 #include "object-enchant/special-object-flags.h"
19 #include "object-hook/hook-expendable.h"
20 #include "object/item-tester-hooker.h"
21 #include "object/item-use-flags.h"
22 #include "object/object-generator.h"
23 #include "object/object-info.h"
24 #include "object/object-kind-hook.h"
25 #include "object/object-kind.h"
26 #include "perception/object-perception.h"
27 #include "player/attack-defense-types.h"
28 #include "player-info/avatar.h"
29 #include "player/digestion-processor.h"
30 #include "player/mimic-info-table.h"
31 #include "player/player-class.h"
32 #include "player/player-damage.h"
33 #include "player/player-race-types.h"
34 #include "player/special-defense-types.h"
35 #include "player/player-status-flags.h"
36 #include "spell-realm/spells-hex.h"
37 #include "spell/spells-status.h"
38 #include "status/action-setter.h"
39 #include "status/bad-status-setter.h"
40 #include "status/base-status.h"
41 #include "status/element-resistance.h"
42 #include "status/experience.h"
43 #include "sv-definition/sv-food-types.h"
44 #include "sv-definition/sv-other-types.h"
45 #include "util/string-processor.h"
46 #include "view/display-messages.h"
47 #include "view/object-describer.h"
48
49 /*!
50  * @brief 食料を食べるコマンドのサブルーチン
51  * @param item 食べるオブジェクトの所持品ID
52  * @return なし
53  */
54 void exe_eat_food(player_type *creature_ptr, INVENTORY_IDX item)
55 {
56     int ident, lev;
57     object_type *o_ptr;
58
59     if (music_singing_any(creature_ptr))
60         stop_singing(creature_ptr);
61     if (hex_spelling_any(creature_ptr))
62         stop_hex_spell_all(creature_ptr);
63     o_ptr = ref_item(creature_ptr, item);
64
65     sound(SOUND_EAT);
66
67     take_turn(creature_ptr, 100);
68
69     /* Identity not known yet */
70     ident = FALSE;
71
72     /* Object level */
73     lev = k_info[o_ptr->k_idx].level;
74
75     if (o_ptr->tval == TV_FOOD) {
76         /* Analyze the food */
77         switch (o_ptr->sval) {
78         case SV_FOOD_POISON: {
79             if (!(has_resist_pois(creature_ptr) || is_oppose_pois(creature_ptr))) {
80                 if (set_poisoned(creature_ptr, creature_ptr->poisoned + randint0(10) + 10)) {
81                     ident = TRUE;
82                 }
83             }
84             break;
85         }
86
87         case SV_FOOD_BLINDNESS: {
88             if (!creature_ptr->resist_blind) {
89                 if (set_blind(creature_ptr, creature_ptr->blind + randint0(200) + 200)) {
90                     ident = TRUE;
91                 }
92             }
93             break;
94         }
95
96         case SV_FOOD_PARANOIA: {
97             if (!creature_ptr->resist_fear) {
98                 if (set_afraid(creature_ptr, creature_ptr->afraid + randint0(10) + 10)) {
99                     ident = TRUE;
100                 }
101             }
102             break;
103         }
104
105         case SV_FOOD_CONFUSION: {
106             if (!has_resist_conf(creature_ptr)) {
107                 if (set_confused(creature_ptr, creature_ptr->confused + randint0(10) + 10)) {
108                     ident = TRUE;
109                 }
110             }
111             break;
112         }
113
114         case SV_FOOD_HALLUCINATION: {
115             if (!has_resist_chaos(creature_ptr)) {
116                 if (set_image(creature_ptr, creature_ptr->image + randint0(250) + 250)) {
117                     ident = TRUE;
118                 }
119             }
120             break;
121         }
122
123         case SV_FOOD_PARALYSIS: {
124             if (!creature_ptr->free_act) {
125                 if (set_paralyzed(creature_ptr, creature_ptr->paralyzed + randint0(10) + 10)) {
126                     ident = TRUE;
127                 }
128             }
129             break;
130         }
131
132         case SV_FOOD_WEAKNESS: {
133             take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);
134             (void)do_dec_stat(creature_ptr, A_STR);
135             ident = TRUE;
136             break;
137         }
138
139         case SV_FOOD_SICKNESS: {
140             take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(6, 6), _("毒入り食料", "poisonous food"), -1);
141             (void)do_dec_stat(creature_ptr, A_CON);
142             ident = TRUE;
143             break;
144         }
145
146         case SV_FOOD_STUPIDITY: {
147             take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);
148             (void)do_dec_stat(creature_ptr, A_INT);
149             ident = TRUE;
150             break;
151         }
152
153         case SV_FOOD_NAIVETY: {
154             take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(8, 8), _("毒入り食料", "poisonous food"), -1);
155             (void)do_dec_stat(creature_ptr, A_WIS);
156             ident = TRUE;
157             break;
158         }
159
160         case SV_FOOD_UNHEALTH: {
161             take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);
162             (void)do_dec_stat(creature_ptr, A_CON);
163             ident = TRUE;
164             break;
165         }
166
167         case SV_FOOD_DISEASE: {
168             take_hit(creature_ptr, DAMAGE_NOESCAPE, damroll(10, 10), _("毒入り食料", "poisonous food"), -1);
169             (void)do_dec_stat(creature_ptr, A_STR);
170             ident = TRUE;
171             break;
172         }
173
174         case SV_FOOD_CURE_POISON: {
175             if (set_poisoned(creature_ptr, 0))
176                 ident = TRUE;
177             break;
178         }
179
180         case SV_FOOD_CURE_BLINDNESS: {
181             if (set_blind(creature_ptr, 0))
182                 ident = TRUE;
183             break;
184         }
185
186         case SV_FOOD_CURE_PARANOIA: {
187             if (set_afraid(creature_ptr, 0))
188                 ident = TRUE;
189             break;
190         }
191
192         case SV_FOOD_CURE_CONFUSION: {
193             if (set_confused(creature_ptr, 0))
194                 ident = TRUE;
195             break;
196         }
197
198         case SV_FOOD_CURE_SERIOUS: {
199             ident = cure_serious_wounds(creature_ptr, 4, 8);
200             break;
201         }
202
203         case SV_FOOD_RESTORE_STR: {
204             if (do_res_stat(creature_ptr, A_STR))
205                 ident = TRUE;
206             break;
207         }
208
209         case SV_FOOD_RESTORE_CON: {
210             if (do_res_stat(creature_ptr, A_CON))
211                 ident = TRUE;
212             break;
213         }
214
215         case SV_FOOD_RESTORING: {
216             ident = restore_all_status(creature_ptr);
217             break;
218         }
219
220 #ifdef JP
221         /* それぞれの食べ物の感想をオリジナルより細かく表現 */
222         case SV_FOOD_BISCUIT: {
223             msg_print("甘くてサクサクしてとてもおいしい。");
224             ident = TRUE;
225             break;
226         }
227
228         case SV_FOOD_JERKY: {
229             msg_print("歯ごたえがあっておいしい。");
230             ident = TRUE;
231             break;
232         }
233
234         case SV_FOOD_SLIME_MOLD: {
235             msg_print("これはなんとも形容しがたい味だ。");
236             ident = TRUE;
237             break;
238         }
239
240         case SV_FOOD_RATION: {
241             msg_print("これはおいしい。");
242             ident = TRUE;
243             break;
244         }
245 #else
246         case SV_FOOD_RATION:
247         case SV_FOOD_BISCUIT:
248         case SV_FOOD_JERKY:
249         case SV_FOOD_SLIME_MOLD: {
250             msg_print("That tastes good.");
251             ident = TRUE;
252             break;
253         }
254 #endif
255
256         case SV_FOOD_WAYBREAD: {
257             msg_print(_("これはひじょうに美味だ。", "That tastes good."));
258             (void)set_poisoned(creature_ptr, 0);
259             (void)hp_player(creature_ptr, damroll(4, 8));
260             ident = TRUE;
261             break;
262         }
263
264         case SV_FOOD_PINT_OF_ALE: {
265             msg_print(_("のどごし爽やかだ。", "That tastes good."));
266             ident = TRUE;
267             break;
268         }
269
270         case SV_FOOD_PINT_OF_WINE: {
271             msg_print(_("のどごし爽やかだ。", "That tastes good."));
272             ident = TRUE;
273             break;
274         }
275         }
276     }
277
278     /*
279      * Store what may have to be updated for the inventory (including
280      * autodestroy if set by something else).  Then turn off those flags
281      * so that updates triggered by calling gain_exp() or set_food() below
282      * do not rearrange the inventory before the food item is destroyed in
283      * the pack.
284      */
285     BIT_FLAGS inventory_flags = (PU_COMBINE | PU_REORDER | (creature_ptr->update & PU_AUTODESTROY));
286     creature_ptr->update &= ~(PU_COMBINE | PU_REORDER | PU_AUTODESTROY);
287
288     if (!(object_is_aware(o_ptr))) {
289         chg_virtue(creature_ptr, V_KNOWLEDGE, -1);
290         chg_virtue(creature_ptr, V_PATIENCE, -1);
291         chg_virtue(creature_ptr, V_CHANCE, 1);
292     }
293
294     /* We have tried it */
295     if (o_ptr->tval == TV_FOOD)
296         object_tried(o_ptr);
297
298     /* The player is now aware of the object */
299     if (ident && !object_is_aware(o_ptr)) {
300         object_aware(creature_ptr, o_ptr);
301         gain_exp(creature_ptr, (lev + (creature_ptr->lev >> 1)) / creature_ptr->lev);
302     }
303
304     creature_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
305
306     /* Food can feed the player */
307     if (is_specific_player_race(creature_ptr, RACE_VAMPIRE) || (creature_ptr->mimic_form == MIMIC_VAMPIRE)) {
308         /* Reduced nutritional benefit */
309         (void)set_food(creature_ptr, creature_ptr->food + (o_ptr->pval / 10));
310         msg_print(_("あなたのような者にとって食糧など僅かな栄養にしかならない。", "Mere victuals hold scant sustenance for a being such as yourself."));
311
312         if (creature_ptr->food < PY_FOOD_ALERT) /* Hungry */
313             msg_print(_("あなたの飢えは新鮮な血によってのみ満たされる!", "Your hunger can only be satisfied with fresh blood!"));
314     } else if ((is_specific_player_race(creature_ptr, RACE_SKELETON) || is_specific_player_race(creature_ptr, RACE_GOLEM)
315                    || is_specific_player_race(creature_ptr, RACE_ZOMBIE) || is_specific_player_race(creature_ptr, RACE_SPECTRE))
316         && (o_ptr->tval == TV_STAFF || o_ptr->tval == TV_WAND)) {
317         concptr staff;
318
319         if (o_ptr->tval == TV_STAFF && (item < 0) && (o_ptr->number > 1)) {
320             creature_ptr->update |= inventory_flags;
321             msg_print(_("まずは杖を拾わなければ。", "You must first pick up the staffs."));
322             return;
323         }
324         staff = (o_ptr->tval == TV_STAFF) ? _("杖", "staff") : _("魔法棒", "wand");
325
326         /* "Eat" charges */
327         if (o_ptr->pval == 0) {
328             msg_format(_("この%sにはもう魔力が残っていない。", "The %s has no charges left."), staff);
329             o_ptr->ident |= (IDENT_EMPTY);
330             creature_ptr->update |= inventory_flags;
331             creature_ptr->window |= (PW_INVEN);
332
333             return;
334         }
335         msg_format(_("あなたは%sの魔力をエネルギー源として吸収した。", "You absorb mana of the %s as your energy."), staff);
336
337         /* Use a single charge */
338         o_ptr->pval--;
339
340         /* Eat a charge */
341         set_food(creature_ptr, creature_ptr->food + 5000);
342
343         /* XXX Hack -- unstack if necessary */
344         if (o_ptr->tval == TV_STAFF && (item >= 0) && (o_ptr->number > 1)) {
345             object_type forge;
346             object_type *q_ptr;
347             q_ptr = &forge;
348             object_copy(q_ptr, o_ptr);
349
350             /* Modify quantity */
351             q_ptr->number = 1;
352
353             /* Restore the charges */
354             o_ptr->pval++;
355
356             /* Unstack the used item */
357             o_ptr->number--;
358             item = store_item_to_inventory(creature_ptr, q_ptr);
359
360             msg_format(_("杖をまとめなおした。", "You unstack your staff."));
361         }
362
363         /* Describe charges in the pack */
364         if (item >= 0) {
365             inven_item_charges(creature_ptr, item);
366         }
367
368         /* Describe charges on the floor */
369         else {
370             floor_item_charges(creature_ptr->current_floor_ptr, 0 - item);
371         }
372
373         creature_ptr->window |= (PW_INVEN | PW_EQUIP);
374         creature_ptr->update |= inventory_flags;
375
376         /* Don't eat a staff/wand itself */
377         return;
378     }
379
380     if ((is_specific_player_race(creature_ptr, RACE_BALROG) || (mimic_info[creature_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_DEMON))
381         && (o_ptr->tval == TV_CORPSE && o_ptr->sval == SV_CORPSE && angband_strchr("pht", r_info[o_ptr->pval].d_char))) {
382         /* Drain vitality of humanoids */
383         GAME_TEXT o_name[MAX_NLEN];
384         describe_flavor(creature_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
385         msg_format(_("%sは燃え上り灰になった。精力を吸収した気がする。", "%^s is burnt to ashes.  You absorb its vitality!"), o_name);
386         (void)set_food(creature_ptr, PY_FOOD_MAX - 1);
387     } else if (is_specific_player_race(creature_ptr, RACE_SKELETON)) {
388         if (!((o_ptr->sval == SV_FOOD_WAYBREAD) || (o_ptr->sval < SV_FOOD_BISCUIT))) {
389             object_type forge;
390             object_type *q_ptr = &forge;
391
392             msg_print(_("食べ物がアゴを素通りして落ちた!", "The food falls through your jaws!"));
393             object_prep(creature_ptr, q_ptr, lookup_kind(o_ptr->tval, o_ptr->sval));
394
395             /* Drop the object from heaven */
396             (void)drop_near(creature_ptr, q_ptr, -1, creature_ptr->y, creature_ptr->x);
397         } else {
398             msg_print(_("食べ物がアゴを素通りして落ち、消えた!", "The food falls through your jaws and vanishes!"));
399         }
400     } else if (is_specific_player_race(creature_ptr, RACE_GOLEM) || is_specific_player_race(creature_ptr, RACE_ZOMBIE)
401         || is_specific_player_race(creature_ptr, RACE_ENT) || is_specific_player_race(creature_ptr, RACE_BALROG)
402         || is_specific_player_race(creature_ptr, RACE_ANDROID) || is_specific_player_race(creature_ptr, RACE_SPECTRE)
403         || (mimic_info[creature_ptr->mimic_form].MIMIC_FLAGS & MIMIC_IS_NONLIVING)) {
404         msg_print(_("生者の食物はあなたにとってほとんど栄養にならない。", "The food of mortals is poor sustenance for you."));
405         set_food(creature_ptr, creature_ptr->food + ((o_ptr->pval) / 20));
406     } else if (o_ptr->tval == TV_FOOD && o_ptr->sval == SV_FOOD_WAYBREAD) {
407         /* Waybread is always fully satisfying. */
408         set_food(creature_ptr, MAX(creature_ptr->food, PY_FOOD_MAX - 1));
409     } else {
410         /* Food can feed the player */
411         (void)set_food(creature_ptr, creature_ptr->food + o_ptr->pval);
412     }
413
414     creature_ptr->update |= inventory_flags;
415     vary_item(creature_ptr, item, -1);
416 }
417
418 /*!
419  * @brief 食料を食べるコマンドのメインルーチン /
420  * Eat some food (from the pack or floor)
421  * @return なし
422  */
423 void do_cmd_eat_food(player_type *creature_ptr)
424 {
425     OBJECT_IDX item;
426     concptr q, s;
427
428     if (creature_ptr->special_defense & (KATA_MUSOU | KATA_KOUKIJIN)) {
429         set_action(creature_ptr, ACTION_NONE);
430     }
431
432     item_tester_hook = item_tester_hook_eatable;
433
434     q = _("どれを食べますか? ", "Eat which item? ");
435     s = _("食べ物がない。", "You have nothing to eat.");
436
437     if (!choose_object(creature_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), 0))
438         return;
439
440     exe_eat_food(creature_ptr, item);
441 }