1 | /* SCCS Id: @(#)eat.c 3.3 1999/12/13 */
2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 | /* #define DEBUG */ /* uncomment to enable new eat code debugging */
7 |
8 | #ifdef DEBUG
9 | # ifdef WIZARD
10 | #define debugpline if (wizard) pline
11 | # else
12 | #define debugpline pline
13 | # endif
14 | #endif
15 |
16 | STATIC_PTR int NDECL(eatmdone);
17 | STATIC_PTR int NDECL(eatfood);
18 | STATIC_PTR int NDECL(opentin);
19 | STATIC_PTR int NDECL(unfaint);
20 |
21 | #ifdef OVLB
22 | STATIC_DCL const char *FDECL(food_xname, (struct obj *,BOOLEAN_P));
23 | STATIC_DCL void FDECL(choke, (struct obj *));
24 | STATIC_DCL void NDECL(recalc_wt);
25 | STATIC_DCL struct obj *FDECL(touchfood, (struct obj *));
26 | STATIC_DCL void NDECL(do_reset_eat);
27 | STATIC_DCL void FDECL(done_eating, (BOOLEAN_P));
28 | STATIC_DCL void FDECL(cprefx, (int));
29 | STATIC_DCL int FDECL(intrinsic_possible, (int,struct permonst *));
30 | STATIC_DCL void FDECL(givit, (int,struct permonst *));
31 | STATIC_DCL void FDECL(cpostfx, (int));
32 | STATIC_DCL void FDECL(start_tin, (struct obj *));
33 | STATIC_DCL int FDECL(eatcorpse, (struct obj *));
34 | STATIC_DCL void FDECL(start_eating, (struct obj *));
35 | STATIC_DCL void FDECL(fprefx, (struct obj *));
36 | STATIC_DCL void FDECL(fpostfx, (struct obj *));
37 | STATIC_DCL int NDECL(bite);
38 |
39 | STATIC_DCL int FDECL(rottenfood, (struct obj *));
40 | STATIC_DCL void NDECL(eatspecial);
41 | STATIC_DCL void FDECL(eataccessory, (struct obj *));
42 | STATIC_DCL const char * FDECL(foodword, (struct obj *));
43 |
44 | char msgbuf[BUFSZ];
45 |
46 | #endif /* OVLB */
47 |
48 | /* hunger texts used on bottom line (each 8 chars long) */
49 | #define SATIATED 0
50 | #define NOT_HUNGRY 1
51 | #define HUNGRY 2
52 | #define WEAK 3
53 | #define FAINTING 4
54 | #define FAINTED 5
55 | #define STARVED 6
56 |
57 | /* also used to see if you're allowed to eat cats and dogs */
58 | #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC))
59 |
60 | #ifndef OVLB
61 |
62 | STATIC_DCL NEARDATA const char comestibles[];
63 | STATIC_DCL NEARDATA const char allobj[];
64 | STATIC_DCL boolean force_save_hs;
65 |
66 | #else
67 |
68 | STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 };
69 |
70 | /* Gold must come first for getobj(). */
71 | STATIC_OVL NEARDATA const char allobj[] = {
72 | GOLD_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS,
73 | WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS,
74 | GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 };
75 |
76 | STATIC_OVL boolean force_save_hs = FALSE;
77 |
78 | const char *hu_stat[] = {
79 | "Satiated",
80 | " ",
81 | "Hungry ",
82 | "Weak ",
83 | "Fainting",
84 | "Fainted ",
85 | "Starved "
86 | };
87 |
88 | #endif /* OVLB */
89 | #ifdef OVL1
90 |
91 | /*
92 | * Decide whether a particular object can be eaten by the possibly
93 | * polymorphed character. Not used for monster checks.
94 | */
95 | boolean
96 | is_edible(obj)
97 | register struct obj *obj;
98 | {
99 | /* protect invocation tools but not Rider corpses (handled elsewhere)*/
100 | /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */
101 | if (objects[obj->otyp].oc_unique)
102 | return FALSE;
103 | /* above also prevents the Amulet from being eaten, so we must never
104 | allow fake amulets to be eaten either [which is already the case] */
105 |
106 | if (metallivorous(youmonst.data) && is_metallic(obj))
107 | return TRUE;
108 | if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) &&
109 | /* [g.cubes can eat containers and retain all contents
110 | as engulfed items, but poly'd player can't do that] */
111 | !Has_contents(obj))
112 | return TRUE;
113 |
114 | /* return((boolean)(!!index(comestibles, obj->oclass))); */
115 | return (boolean)(obj->oclass == FOOD_CLASS);
116 | }
117 |
118 | #endif /* OVL1 */
119 | #ifdef OVLB
120 |
121 | void
122 | init_uhunger()
123 | {
124 | u.uhunger = 900;
125 | u.uhs = NOT_HUNGRY;
126 | }
127 |
128 | static const struct { const char *txt; int nut; } tintxts[] = {
129 | {"deep fried", 60},
130 | {"pickled", 40},
131 | {"soup made from", 20},
132 | {"pureed", 500},
133 | #define ROTTEN_TIN 4
134 | {"rotten", -50},
135 | #define HOMEMADE_TIN 5
136 | {"homemade", 50},
137 | {"stir fried", 80},
138 | {"candied", 100},
139 | {"boiled", 50},
140 | {"dried", 55},
141 | {"szechuan", 70},
142 | {"french fried", 40},
143 | {"sauteed", 95},
144 | {"broiled", 80},
145 | {"smoked", 50},
146 | {"", 0}
147 | };
148 | #define TTSZ SIZE(tintxts)
149 |
150 | static NEARDATA struct {
151 | struct obj *tin;
152 | int usedtime, reqtime;
153 | } tin;
154 |
155 | static NEARDATA struct {
156 | struct obj *piece; /* the thing being eaten, or last thing that
157 | * was partially eaten, unless that thing was
158 | * a tin, which uses the tin structure above,
159 | * in which case this should be 0 */
160 | /* doeat() initializes these when piece is valid */
161 | int usedtime, /* turns spent eating */
162 | reqtime; /* turns required to eat */
163 | int nmod; /* coded nutrition per turn */
164 | Bitfield(canchoke,1); /* was satiated at beginning */
165 |
166 | /* start_eating() initializes these */
167 | Bitfield(fullwarn,1); /* have warned about being full */
168 | Bitfield(eating,1); /* victual currently being eaten */
169 | Bitfield(doreset,1); /* stop eating at end of turn */
170 | } victual;
171 |
172 | static char *eatmbuf = 0; /* set by cpostfx() */
173 |
174 | STATIC_PTR
175 | int
176 | eatmdone() /* called after mimicing is over */
177 | {
178 | /* release `eatmbuf' */
179 | if (eatmbuf) {
180 | if (nomovemsg == eatmbuf) nomovemsg = 0;
181 | free((genericptr_t)eatmbuf), eatmbuf = 0;
182 | }
183 | /* update display */
184 | if (youmonst.m_ap_type) {
185 | youmonst.m_ap_type = M_AP_NOTHING;
186 | newsym(u.ux,u.uy);
187 | }
188 | return 0;
189 | }
190 |
191 | /* ``[the(] singular(food, xname) [)]'' with awareness of unique monsters */
192 | STATIC_OVL const char *
193 | food_xname(food, the_pfx)
194 | struct obj *food;
195 | boolean the_pfx;
196 | {
197 | const char *result;
198 | int mnum = food->corpsenm;
199 |
200 | if (food->otyp == CORPSE && (mons[mnum].geno & G_UNIQ)) {
201 | /* grab xname()'s modifiable return buffer for our own use */
202 | char *bufp = xname(food);
203 | Sprintf(bufp, "%s%s corpse",
204 | (the_pfx && !type_is_pname(&mons[mnum])) ? "the " : "",
205 | s_suffix(mons[mnum].mname));
206 | result = bufp;
207 | } else {
208 | /* the ordinary case */
209 | result = singular(food, xname);
210 | if (the_pfx) result = the(result);
211 | }
212 | return result;
213 | }
214 |
215 | /* Created by GAN 01/28/87
216 | * Amended by AKP 09/22/87: if not hard, don't choke, just vomit.
217 | * Amended by 3. 06/12/89: if not hard, sometimes choke anyway, to keep risk.
218 | * 11/10/89: if hard, rarely vomit anyway, for slim chance.
219 | */
220 | STATIC_OVL void
221 | choke(food) /* To a full belly all food is bad. (It.) */
222 | register struct obj *food;
223 | {
224 | /* only happens if you were satiated */
225 | if (u.uhs != SATIATED) {
226 | if (food->otyp != AMULET_OF_STRANGULATION)
227 | return;
228 | } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) {
229 | adjalign(-1); /* gluttony is unchivalrous */
230 | You_feel("like a glutton!");
231 | }
232 |
233 | exercise(A_CON, FALSE);
234 |
235 | if (Breathless || (!Strangled && !rn2(20))) {
236 | /* choking by eating AoS doesn't involve stuffing yourself */
237 | if (food->otyp == AMULET_OF_STRANGULATION) {
238 | You("choke, but recover your composure.");
239 | return;
240 | }
241 | You("stuff yourself and then vomit voluminously.");
242 | morehungry(1000); /* you just got *very* sick! */
243 | vomit();
244 | } else {
245 | killer_format = KILLED_BY_AN;
246 | /*
247 | * Note all "killer"s below read "Choked on %s" on the
248 | * high score list & tombstone. So plan accordingly.
249 | */
250 | if(food) {
251 | You("choke over your %s.", foodword(food));
252 | if (food->oclass == GOLD_CLASS) {
253 | killer = "a very rich meal";
254 | } else {
255 | killer = food_xname(food, FALSE);
256 | }
257 | } else {
258 | You("choke over it.");
259 | killer = "quick snack";
260 | }
261 | You("die...");
262 | done(CHOKING);
263 | }
264 | }
265 |
266 | STATIC_OVL void
267 | recalc_wt() /* modify object wt. depending on time spent consuming it */
268 | {
269 | register struct obj *piece = victual.piece;
270 |
271 | #ifdef DEBUG
272 | debugpline("Old weight = %d", piece->owt);
273 | debugpline("Used time = %d, Req'd time = %d",
274 | victual.usedtime, victual.reqtime);
275 | #endif
276 | /* weight(piece) = weight of full item */
277 | if(victual.usedtime)
278 | piece->owt = eaten_stat(weight(piece), piece);
279 | #ifdef DEBUG
280 | debugpline("New weight = %d", piece->owt);
281 | #endif
282 | }
283 |
284 | void
285 | reset_eat() /* called when eating interrupted by an event */
286 | {
287 | /* we only set a flag here - the actual reset process is done after
288 | * the round is spent eating.
289 | */
290 | if(victual.eating && !victual.doreset) {
291 | #ifdef DEBUG
292 | debugpline("reset_eat...");
293 | #endif
294 | victual.doreset = TRUE;
295 | }
296 | return;
297 | }
298 |
299 | STATIC_OVL struct obj *
300 | touchfood(otmp)
301 | register struct obj *otmp;
302 | {
303 | if (otmp->quan > 1L) {
304 | if(!carried(otmp))
305 | (void) splitobj(otmp, 1L);
306 | else
307 | otmp = splitobj(otmp, otmp->quan - 1L);
308 | #ifdef DEBUG
309 | debugpline("split object,");
310 | #endif
311 | }
312 |
313 | if (!otmp->oeaten) {
314 | if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) &&
315 | !otmp->no_charge)
316 | || otmp->unpaid) &&
317 | (otmp->otyp == CORPSE || objects[otmp->otyp].oc_delay > 1)) {
318 | /* create a dummy duplicate to put on bill */
319 | verbalize("You bit it, you bought it!");
320 | bill_dummy_object(otmp);
321 | }
322 | otmp->oeaten = (otmp->otyp == CORPSE ?
323 | mons[otmp->corpsenm].cnutrit :
324 | objects[otmp->otyp].oc_nutrition);
325 | }
326 |
327 | if (carried(otmp)) {
328 | freeinv(otmp);
329 | if (inv_cnt() >= 52 && !merge_choice(invent, otmp))
330 | dropy(otmp);
331 | else
332 | otmp = addinv(otmp); /* unlikely but a merge is possible */
333 | }
334 | return(otmp);
335 | }
336 |
337 | /* When food decays, in the middle of your meal, we don't want to dereference
338 | * any dangling pointers, so set it to null (which should still trigger
339 | * do_reset_eat() at the beginning of eatfood()) and check for null pointers
340 | * in do_reset_eat().
341 | */
342 | void
343 | food_disappears(obj)
344 | register struct obj *obj;
345 | {
346 | if (obj == victual.piece) victual.piece = (struct obj *)0;
347 | if (obj->timed) obj_stop_timers(obj);
348 | }
349 |
350 | /* renaming an object usually results in it having a different address;
351 | so the sequence start eating/opening, get interrupted, name the food,
352 | resume eating/opening would restart from scratch */
353 | void
354 | food_substitution(old_obj, new_obj)
355 | struct obj *old_obj, *new_obj;
356 | {
357 | if (old_obj == victual.piece) victual.piece = new_obj;
358 | if (old_obj == tin.tin) tin.tin = new_obj;
359 | }
360 |
361 | STATIC_OVL void
362 | do_reset_eat()
363 | {
364 | #ifdef DEBUG
365 | debugpline("do_reset_eat...");
366 | #endif
367 | if (victual.piece) {
368 | victual.piece = touchfood(victual.piece);
369 | recalc_wt();
370 | }
371 | victual.fullwarn = victual.eating = victual.doreset = FALSE;
372 | /* Do not set canchoke to FALSE; if we continue eating the same object
373 | * we need to know if canchoke was set when they started eating it the
374 | * previous time. And if we don't continue eating the same object
375 | * canchoke always gets recalculated anyway.
376 | */
377 | stop_occupation();
378 | newuhs(FALSE);
379 | }
380 |
381 | STATIC_PTR
382 | int
383 | eatfood() /* called each move during eating process */
384 | {
385 | if(!victual.piece ||
386 | (!carried(victual.piece) && !obj_here(victual.piece, u.ux, u.uy))) {
387 | /* maybe it was stolen? */
388 | do_reset_eat();
389 | return(0);
390 | }
391 | if(!victual.eating) return(0);
392 |
393 | if(++victual.usedtime <= victual.reqtime) {
394 | if(bite()) return(0);
395 | return(1); /* still busy */
396 | } else { /* done */
397 | done_eating(TRUE);
398 | return(0);
399 | }
400 | }
401 |
402 | STATIC_OVL void
403 | done_eating(message)
404 | boolean message;
405 | {
406 | victual.piece->in_use = TRUE;
407 | occupation = 0; /* do this early, so newuhs() knows we're done */
408 | newuhs(FALSE);
409 | if (nomovemsg) {
410 | if (message) pline(nomovemsg);
411 | nomovemsg = 0;
412 | } else if (message)
413 | You("finish eating %s.", food_xname(victual.piece, TRUE));
414 |
415 | if(victual.piece->otyp == CORPSE)
416 | cpostfx(victual.piece->corpsenm);
417 | else
418 | fpostfx(victual.piece);
419 |
420 | if (carried(victual.piece)) useup(victual.piece);
421 | else useupf(victual.piece, 1L);
422 | victual.piece = (struct obj *) 0;
423 | victual.fullwarn = victual.eating = victual.doreset = FALSE;
424 | }
425 |
426 | STATIC_OVL void
427 | cprefx(pm)
428 | register int pm;
429 | {
430 | if (!CANNIBAL_ALLOWED() && your_race(&mons[pm])) {
431 | if (Upolyd)
432 | You("have a bad feeling deep inside.");
433 | You("cannibal! You will regret this!");
434 | HAggravate_monster |= FROMOUTSIDE;
435 | change_luck(-rn1(4,2)); /* -5..-2 */
436 | }
437 |
438 | if (touch_petrifies(&mons[pm]) || pm == PM_MEDUSA) {
439 | if (!Stone_resistance &&
440 | !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
441 | Sprintf(killer_buf, "tasting %s meat", mons[pm].mname);
442 | killer_format = KILLED_BY;
443 | killer = killer_buf;
444 | You("turn to stone.");
445 | done(STONING);
446 | if (victual.piece)
447 | victual.eating = FALSE;
448 | return; /* lifesaved */
449 | }
450 | }
451 |
452 | switch(pm) {
453 | case PM_LITTLE_DOG:
454 | case PM_DOG:
455 | case PM_LARGE_DOG:
456 | case PM_KITTEN:
457 | case PM_HOUSECAT:
458 | case PM_LARGE_CAT:
459 | if (!CANNIBAL_ALLOWED()) {
460 | You_feel("that eating the %s was a bad idea.", mons[pm].mname);
461 | HAggravate_monster |= FROMOUTSIDE;
462 | }
463 | break;
464 | case PM_LIZARD:
465 | if (Stoned) fix_petrification();
466 | break;
467 | case PM_DEATH:
468 | case PM_PESTILENCE:
469 | case PM_FAMINE:
470 | { char buf[BUFSZ];
471 | pline("Eating that is instantly fatal.");
472 | Sprintf(buf, "unwisely ate the body of %s",
473 | mons[pm].mname);
474 | killer = buf;
475 | killer_format = NO_KILLER_PREFIX;
476 | done(DIED);
477 | /* It so happens that since we know these monsters */
478 | /* cannot appear in tins, victual.piece will always */
479 | /* be what we want, which is not generally true. */
480 | if (revive_corpse(victual.piece))
481 | victual.piece = (struct obj *)0;
482 | return;
483 | }
484 | case PM_GREEN_SLIME:
485 | if (!Unchanging && youmonst.data != &mons[PM_FIRE_VORTEX] &&
486 | youmonst.data != &mons[PM_FIRE_ELEMENTAL] &&
487 | youmonst.data != &mons[PM_GREEN_SLIME]) {
488 | You("don't feel very well.");
489 | Slimed = 10L;
490 | }
491 | /* Fall through */
492 | default:
493 | if (acidic(&mons[pm]) && Stoned)
494 | fix_petrification();
495 | break;
496 | }
497 | }
498 |
499 | void
500 | fix_petrification()
501 | {
502 | Stoned = 0;
503 | delayed_killer = 0;
504 | if (Hallucination)
505 | pline("What a pity - you just ruined a future piece of %sart!",
506 | ACURR(A_CHA) > 15 ? "fine " : "");
507 | else
508 | You_feel("limber!");
509 | }
510 |
511 | /*
512 | * If you add an intrinsic that can be gotten by eating a monster, add it
513 | * to intrinsic_possible() and givit(). (It must already be in prop.h to
514 | * be an intrinsic property.)
515 | * It would be very easy to make the intrinsics not try to give you one
516 | * that you already had by checking to see if you have it in
517 | * intrinsic_possible() instead of givit().
518 | */
519 |
520 | /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */
521 | STATIC_OVL int
522 | intrinsic_possible(type, ptr)
523 | int type;
524 | register struct permonst *ptr;
525 | {
526 | switch (type) {
527 | case FIRE_RES:
528 | #ifdef DEBUG
529 | if (ptr->mconveys & MR_FIRE) {
530 | debugpline("can get fire resistance");
531 | return(TRUE);
532 | } else return(FALSE);
533 | #else
534 | return(ptr->mconveys & MR_FIRE);
535 | #endif
536 | case SLEEP_RES:
537 | #ifdef DEBUG
538 | if (ptr->mconveys & MR_SLEEP) {
539 | debugpline("can get sleep resistance");
540 | return(TRUE);
541 | } else return(FALSE);
542 | #else
543 | return(ptr->mconveys & MR_SLEEP);
544 | #endif
545 | case COLD_RES:
546 | #ifdef DEBUG
547 | if (ptr->mconveys & MR_COLD) {
548 | debugpline("can get cold resistance");
549 | return(TRUE);
550 | } else return(FALSE);
551 | #else
552 | return(ptr->mconveys & MR_COLD);
553 | #endif
554 | case DISINT_RES:
555 | #ifdef DEBUG
556 | if (ptr->mconveys & MR_DISINT) {
557 | debugpline("can get disintegration resistance");
558 | return(TRUE);
559 | } else return(FALSE);
560 | #else
561 | return(ptr->mconveys & MR_DISINT);
562 | #endif
563 | case SHOCK_RES: /* shock (electricity) resistance */
564 | #ifdef DEBUG
565 | if (ptr->mconveys & MR_ELEC) {
566 | debugpline("can get shock resistance");
567 | return(TRUE);
568 | } else return(FALSE);
569 | #else
570 | return(ptr->mconveys & MR_ELEC);
571 | #endif
572 | case POISON_RES:
573 | #ifdef DEBUG
574 | if (ptr->mconveys & MR_POISON) {
575 | debugpline("can get poison resistance");
576 | return(TRUE);
577 | } else return(FALSE);
578 | #else
579 | return(ptr->mconveys & MR_POISON);
580 | #endif
581 | case TELEPORT:
582 | #ifdef DEBUG
583 | if (can_teleport(ptr)) {
584 | debugpline("can get teleport");
585 | return(TRUE);
586 | } else return(FALSE);
587 | #else
588 | return(can_teleport(ptr));
589 | #endif
590 | case TELEPORT_CONTROL:
591 | #ifdef DEBUG
592 | if (control_teleport(ptr)) {
593 | debugpline("can get teleport control");
594 | return(TRUE);
595 | } else return(FALSE);
596 | #else
597 | return(control_teleport(ptr));
598 | #endif
599 | case TELEPAT:
600 | #ifdef DEBUG
601 | if (telepathic(ptr)) {
602 | debugpline("can get telepathy");
603 | return(TRUE);
604 | } else return(FALSE);
605 | #else
606 | return(telepathic(ptr));
607 | #endif
608 | default:
609 | return(FALSE);
610 | }
611 | /*NOTREACHED*/
612 | }
613 |
614 | /* givit() tries to give you an intrinsic based on the monster's level
615 | * and what type of intrinsic it is trying to give you.
616 | */
617 | STATIC_OVL void
618 | givit(type, ptr)
619 | int type;
620 | register struct permonst *ptr;
621 | {
622 | register int chance;
623 |
624 | #ifdef DEBUG
625 | debugpline("Attempting to give intrinsic %d", type);
626 | #endif
627 | /* some intrinsics are easier to get than others */
628 | switch (type) {
629 | case POISON_RES:
630 | if ((ptr == &mons[PM_KILLER_BEE] ||
631 | ptr == &mons[PM_SCORPION]) && !rn2(4))
632 | chance = 1;
633 | else
634 | chance = 15;
635 | break;
636 | case TELEPORT:
637 | chance = 10;
638 | break;
639 | case TELEPORT_CONTROL:
640 | chance = 12;
641 | break;
642 | case TELEPAT:
643 | chance = 1;
644 | break;
645 | default:
646 | chance = 15;
647 | break;
648 | }
649 |
650 | if (ptr->mlevel <= rn2(chance))
651 | return; /* failed die roll */
652 |
653 | switch (type) {
654 | case FIRE_RES:
655 | #ifdef DEBUG
656 | debugpline("Trying to give fire resistance");
657 | #endif
658 | if(!(HFire_resistance & FROMOUTSIDE)) {
659 | You(Hallucination ? "be chillin'." :
660 | "feel a momentary chill.");
661 | HFire_resistance |= FROMOUTSIDE;
662 | }
663 | break;
664 | case SLEEP_RES:
665 | #ifdef DEBUG
666 | debugpline("Trying to give sleep resistance");
667 | #endif
668 | if(!(HSleep_resistance & FROMOUTSIDE)) {
669 | You_feel("wide awake.");
670 | HSleep_resistance |= FROMOUTSIDE;
671 | }
672 | break;
673 | case COLD_RES:
674 | #ifdef DEBUG
675 | debugpline("Trying to give cold resistance");
676 | #endif
677 | if(!(HCold_resistance & FROMOUTSIDE)) {
678 | You_feel("full of hot air.");
679 | HCold_resistance |= FROMOUTSIDE;
680 | }
681 | break;
682 | case DISINT_RES:
683 | #ifdef DEBUG
684 | debugpline("Trying to give disintegration resistance");
685 | #endif
686 | if(!(HDisint_resistance & FROMOUTSIDE)) {
687 | You_feel(Hallucination ?
688 | "totally together, man." :
689 | "very firm.");
690 | HDisint_resistance |= FROMOUTSIDE;
691 | }
692 | break;
693 | case SHOCK_RES: /* shock (electricity) resistance */
694 | #ifdef DEBUG
695 | debugpline("Trying to give shock resistance");
696 | #endif
697 | if(!(HShock_resistance & FROMOUTSIDE)) {
698 | if (Hallucination)
699 | You_feel("grounded in reality.");
700 | else
701 | Your("health currently feels amplified!");
702 | HShock_resistance |= FROMOUTSIDE;
703 | }
704 | break;
705 | case POISON_RES:
706 | #ifdef DEBUG
707 | debugpline("Trying to give poison resistance");
708 | #endif
709 | if(!(HPoison_resistance & FROMOUTSIDE)) {
710 | You_feel(Poison_resistance ?
711 | "especially healthy." : "healthy.");
712 | HPoison_resistance |= FROMOUTSIDE;
713 | }
714 | break;
715 | case TELEPORT:
716 | #ifdef DEBUG
717 | debugpline("Trying to give teleport");
718 | #endif
719 | if(!(HTeleportation & FROMOUTSIDE)) {
720 | You_feel(Hallucination ? "diffuse." :
721 | "very jumpy.");
722 | HTeleportation |= FROMOUTSIDE;
723 | }
724 | break;
725 | case TELEPORT_CONTROL:
726 | #ifdef DEBUG
727 | debugpline("Trying to give teleport control");
728 | #endif
729 | if(!(HTeleport_control & FROMOUTSIDE)) {
730 | You_feel(Hallucination ?
731 | "centered in your personal space." :
732 | "in control of yourself.");
733 | HTeleport_control |= FROMOUTSIDE;
734 | }
735 | break;
736 | case TELEPAT:
737 | #ifdef DEBUG
738 | debugpline("Trying to give telepathy");
739 | #endif
740 | if(!(HTelepat & FROMOUTSIDE)) {
741 | You_feel(Hallucination ?
742 | "in touch with the cosmos." :
743 | "a strange mental acuity.");
744 | HTelepat |= FROMOUTSIDE;
745 | /* If blind, make sure monsters show up. */
746 | if (Blind) see_monsters();
747 | }
748 | break;
749 | default:
750 | #ifdef DEBUG
751 | debugpline("Tried to give an impossible intrinsic");
752 | #endif
753 | break;
754 | }
755 | }
756 |
757 | STATIC_OVL void
758 | cpostfx(pm) /* called after completely consuming a corpse */
759 | register int pm;
760 | {
761 | register int tmp = 0;
762 |
763 | /* in case `afternmv' didn't get called for previously mimicking
764 | gold, clean up now to avoid `eatmbuf' memory leak */
765 | if (eatmbuf) (void)eatmdone();
766 |
767 | switch(pm) {
768 | case PM_WRAITH:
769 | pluslvl(FALSE);
770 | break;
771 | case PM_HUMAN_WERERAT:
772 | u.ulycn = PM_WERERAT;
773 | break;
774 | case PM_HUMAN_WEREJACKAL:
775 | u.ulycn = PM_WEREJACKAL;
776 | break;
777 | case PM_HUMAN_WEREWOLF:
778 | u.ulycn = PM_WEREWOLF;
779 | break;
780 | case PM_NURSE:
781 | if (Upolyd) u.mh = u.mhmax;
782 | else u.uhp = u.uhpmax;
783 | flags.botl = 1;
784 | break;
785 | case PM_STALKER:
786 | if(!Invis) {
787 | set_itimeout(&HInvis, (long)rn1(100, 50));
788 | } else {
789 | if (!(HInvis & INTRINSIC)) You_feel("hidden!");
790 | HInvis |= FROMOUTSIDE;
791 | HSee_invisible |= FROMOUTSIDE;
792 | }
793 | newsym(u.ux, u.uy);
794 | /* fall into next case */
795 | case PM_YELLOW_LIGHT:
796 | /* fall into next case */
797 | case PM_GIANT_BAT:
798 | make_stunned(HStun + 30,FALSE);
799 | /* fall into next case */
800 | case PM_BAT:
801 | make_stunned(HStun + 30,FALSE);
802 | break;
803 | case PM_GIANT_MIMIC:
804 | tmp += 10;
805 | /* fall into next case */
806 | case PM_LARGE_MIMIC:
807 | tmp += 20;
808 | /* fall into next case */
809 | case PM_SMALL_MIMIC:
810 | tmp += 20;
811 | if (youmonst.data->mlet != S_MIMIC) {
812 | char buf[BUFSZ];
813 |
814 | You_cant("resist the temptation to mimic a pile of gold.");
815 | nomul(-tmp);
816 | Sprintf(buf, "You now prefer mimicking %s again.",
817 | an(Upolyd ? youmonst.data->mname : urace.noun));
818 | eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf);
819 | nomovemsg = eatmbuf;
820 | afternmv = eatmdone;
821 | /* ??? what if this was set before? */
822 | youmonst.m_ap_type = M_AP_OBJECT;
823 | youmonst.mappearance = GOLD_PIECE;
824 | newsym(u.ux,u.uy);
825 | curs_on_u();
826 | /* make gold symbol show up now */
827 | display_nhwindow(WIN_MAP, TRUE);
828 | }
829 | break;
830 | case PM_QUANTUM_MECHANIC:
831 | Your("velocity suddenly seems very uncertain!");
832 | if (HFast & INTRINSIC) {
833 | HFast &= ~INTRINSIC;
834 | You("seem slower.");
835 | } else {
836 | HFast |= FROMOUTSIDE;
837 | You("seem faster.");
838 | }
839 | break;
840 | case PM_LIZARD:
841 | if (HStun > 2) make_stunned(2L,FALSE);
842 | if (HConfusion > 2) make_confused(2L,FALSE);
843 | break;
844 | case PM_CHAMELEON:
845 | case PM_DOPPELGANGER:
846 | /* case PM_SANDESTIN: */
847 | if (!Unchanging) {
848 | You_feel("a change coming over you.");
849 | polyself();
850 | }
851 | break;
852 | case PM_MIND_FLAYER:
853 | case PM_MASTER_MIND_FLAYER:
854 | if (ABASE(A_INT) < ATTRMAX(A_INT)) {
855 | if (!rn2(2)) {
856 | pline("Yum! That was real brain food!");
857 | (void) adjattrib(A_INT, 1, FALSE);
858 | break; /* don't give them telepathy, too */
859 | }
860 | }
861 | else {
862 | pline("For some reason, that tasted bland.");
863 | }
864 | /* fall through to default case */
865 | default: {
866 | register struct permonst *ptr = &mons[pm];
867 | int i, count;
868 |
869 | if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) ||
870 | pm == PM_VIOLET_FUNGUS) {
871 | pline ("Oh wow! Great stuff!");
872 | make_hallucinated(HHallucination + 200,FALSE,0L);
873 | }
874 | if(is_giant(ptr)) gainstr((struct obj *)0, 0);
875 |
876 | /* Check the monster for all of the intrinsics. If this
877 | * monster can give more than one, pick one to try to give
878 | * from among all it can give.
879 | *
880 | * If a monster can give 4 intrinsics then you have
881 | * a 1/1 * 1/2 * 2/3 * 3/4 = 1/4 chance of getting the first,
882 | * a 1/2 * 2/3 * 3/4 = 1/4 chance of getting the second,
883 | * a 1/3 * 3/4 = 1/4 chance of getting the third,
884 | * and a 1/4 chance of getting the fourth.
885 | *
886 | * And now a proof by induction:
887 | * it works for 1 intrinsic (1 in 1 of getting it)
888 | * for 2 you have a 1 in 2 chance of getting the second,
889 | * otherwise you keep the first
890 | * for 3 you have a 1 in 3 chance of getting the third,
891 | * otherwise you keep the first or the second
892 | * for n+1 you have a 1 in n+1 chance of getting the (n+1)st,
893 | * otherwise you keep the previous one.
894 | * Elliott Kleinrock, October 5, 1990
895 | */
896 |
897 | count = 0; /* number of possible intrinsics */
898 | tmp = 0; /* which one we will try to give */
899 | for (i = 1; i <= LAST_PROP; i++) {
900 | if (intrinsic_possible(i, ptr)) {
901 | count++;
902 | /* a 1 in count chance of replacing the old
903 | * one with this one, and a count-1 in count
904 | * chance of keeping the old one. (note
905 | * that 1 in 1 and 0 in 1 are what we want
906 | * for the first one
907 | */
908 | if (!rn2(count)) {
909 | #ifdef DEBUG
910 | debugpline("Intrinsic %d replacing %d",
911 | i, tmp);
912 | #endif
913 | tmp = i;
914 | }
915 | }
916 | }
917 |
918 | /* if any found try to give them one */
919 | if (count) givit(tmp, ptr);
920 | }
921 | break;
922 | }
923 | return;
924 | }
925 |
926 | void
927 | violated_vegetarian()
928 | {
929 | u.uconduct.unvegetarian++;
930 | if (Role_if(PM_MONK)) {
931 | You_feel("guilty.");
932 | adjalign(-1);
933 | }
934 | return;
935 | }
936 |
937 | STATIC_PTR
938 | int
939 | opentin() /* called during each move whilst opening a tin */
940 | {
941 | register int r;
942 | const char *what;
943 | int which;
944 |
945 | if(!carried(tin.tin) && !obj_here(tin.tin, u.ux, u.uy))
946 | /* perhaps it was stolen? */
947 | return(0); /* %% probably we should use tinoid */
948 | if(tin.usedtime++ >= 50) {
949 | You("give up your attempt to open the tin.");
950 | return(0);
951 | }
952 | if(tin.usedtime < tin.reqtime)
953 | return(1); /* still busy */
954 | if(tin.tin->otrapped ||
955 | (tin.tin->cursed && tin.tin->spe != -1 && !rn2(8))) {
956 | b_trapped("tin", 0);
957 | goto use_me;
958 | }
959 | You("succeed in opening the tin.");
960 | if(tin.tin->spe != 1) {
961 | if (tin.tin->corpsenm == NON_PM) {
962 | pline("It turns out to be empty.");
963 | tin.tin->dknown = tin.tin->known = TRUE;
964 | goto use_me;
965 | }
966 | r = tin.tin->cursed ? ROTTEN_TIN : /* always rotten if cursed */
967 | (tin.tin->spe == -1) ? HOMEMADE_TIN : /* player made it */
968 | rn2(TTSZ-1); /* else take your pick */
969 | if (r == ROTTEN_TIN && (tin.tin->corpsenm == PM_LIZARD ||
970 | tin.tin->corpsenm == PM_LICHEN))
971 | r = HOMEMADE_TIN; /* lizards don't rot */
972 | else if (tin.tin->spe == -1 && !tin.tin->blessed && !rn2(7))
973 | r = ROTTEN_TIN; /* some homemade tins go bad */
974 | which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */
975 | if (Hallucination) {
976 | what = rndmonnam();
977 | } else {
978 | what = mons[tin.tin->corpsenm].mname;
979 | if (mons[tin.tin->corpsenm].geno & G_UNIQ)
980 | which = type_is_pname(&mons[tin.tin->corpsenm]) ? 1 : 2;
981 | }
982 | if (which == 0) what = makeplural(what);
983 | pline("It smells like %s%s.", (which == 2) ? "the " : "", what);
984 | if (yn("Eat it?") == 'n') {
985 | if (!Hallucination) tin.tin->dknown = tin.tin->known = TRUE;
986 | if (flags.verbose) You("discard the open tin.");
987 | goto use_me;
988 | }
989 | /* in case stop_occupation() was called on previous meal */
990 | victual.piece = (struct obj *)0;
991 | victual.fullwarn = victual.eating = victual.doreset = FALSE;
992 |
993 | You("consume %s %s.", tintxts[r].txt,
994 | mons[tin.tin->corpsenm].mname);
995 |
996 | /* KMH, conduct */
997 | u.uconduct.food++;
998 | if (!vegan(&mons[tin.tin->corpsenm]))
999 | u.uconduct.unvegan++;
1000 | if (!vegetarian(&mons[tin.tin->corpsenm]))
1001 | violated_vegetarian();
1002 |
1003 | tin.tin->dknown = tin.tin->known = TRUE;
1004 | cprefx(tin.tin->corpsenm); cpostfx(tin.tin->corpsenm);
1005 |
1006 | /* check for vomiting added by GAN 01/16/87 */
1007 | if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE);
1008 | else lesshungry(tintxts[r].nut);
1009 |
1010 | if(r == 0) { /* Deep Fried */
1011 | /* Assume !Glib, because you can't open tins when Glib. */
1012 | incr_itimeout(&Glib, rnd(15));
1013 | pline("Eating deep fried food made your %s very slippery.",
1014 | makeplural(body_part(FINGER)));
1015 | }
1016 | } else {
1017 | if (tin.tin->cursed)
1018 | pline("It contains some decaying %s substance.",
1019 | hcolor(green));
1020 | else
1021 | pline("It contains spinach.");
1022 |
1023 | if (yn("Eat it?") == 'n') {
1024 | if (!Hallucination && !tin.tin->cursed)
1025 | tin.tin->dknown = tin.tin->known = TRUE;
1026 | if (flags.verbose)
1027 | You("discard the open tin.");
1028 | goto use_me;
1029 | }
1030 | if (!tin.tin->cursed)
1031 | pline("This makes you feel like %s!",
1032 | Hallucination ? "Swee'pea" : "Popeye");
1033 | lesshungry(600);
1034 | gainstr(tin.tin, 0);
1035 | u.uconduct.food++;
1036 | }
1037 | tin.tin->dknown = tin.tin->known = TRUE;
1038 | use_me:
1039 | if (carried(tin.tin)) useup(tin.tin);
1040 | else useupf(tin.tin, 1L);
1041 | tin.tin = (struct obj *) 0;
1042 | return(0);
1043 | }
1044 |
1045 | STATIC_OVL void
1046 | start_tin(otmp) /* called when starting to open a tin */
1047 | register struct obj *otmp;
1048 | {
1049 | register int tmp;
1050 |
1051 | if (metallivorous(youmonst.data)) {
1052 | You("bite right into the metal tin...");
1053 | tmp = 1;
1054 | } else if (nolimbs(youmonst.data)) {
1055 | You("cannot handle the tin properly to open it.");
1056 | return;
1057 | } else if (otmp->blessed) {
1058 | pline_The("tin opens like magic!");
1059 | tmp = 1;
1060 | } else if(uwep) {
1061 | switch(uwep->otyp) {
1062 | case TIN_OPENER:
1063 | tmp = 1;
1064 | break;
1065 | case DAGGER:
1066 | case SILVER_DAGGER:
1067 | case ELVEN_DAGGER:
1068 | case ORCISH_DAGGER:
1069 | case ATHAME:
1070 | case CRYSKNIFE:
1071 | tmp = 3;
1072 | break;
1073 | case PICK_AXE:
1074 | case AXE:
1075 | tmp = 6;
1076 | break;
1077 | default:
1078 | goto no_opener;
1079 | }
1080 | pline("Using your %s you try to open the tin.",
1081 | aobjnam(uwep, (char *)0));
1082 | } else {
1083 | no_opener:
1084 | pline("It is not so easy to open this tin.");
1085 | if(Glib) {
1086 | pline_The("tin slips from your %s.",
1087 | makeplural(body_part(FINGER)));
1088 | if(otmp->quan > 1L) {
1089 | register struct obj *obj;
1090 | obj = splitobj(otmp, 1L);
1091 | if (otmp == uwep) setuwep(obj);
1092 | if (otmp == uswapwep) setuswapwep(obj);
1093 | if (otmp == uquiver) setuqwep(obj);
1094 | }
1095 | if (carried(otmp)) dropx(otmp);
1096 | else stackobj(otmp);
1097 | return;
1098 | }
1099 | tmp = rn1(1 + 500/((int)(ACURR(A_DEX) + ACURRSTR)), 10);
1100 | }
1101 | tin.reqtime = tmp;
1102 | tin.usedtime = 0;
1103 | tin.tin = otmp;
1104 | set_occupation(opentin, "opening the tin", 0);
1105 | return;
1106 | }
1107 |
1108 | int
1109 | Hear_again() /* called when waking up after fainting */
1110 | {
1111 | flags.soundok = 1;
1112 | return 0;
1113 | }
1114 |
1115 | /* called on the "first bite" of rotten food */
1116 | STATIC_OVL int
1117 | rottenfood(obj)
1118 | struct obj *obj;
1119 | {
1120 | pline("Blecch! Rotten %s!", foodword(obj));
1121 | if(!rn2(4)) {
1122 | if (Hallucination) You_feel("rather trippy.");
1123 | else You_feel("rather %s.", body_part(LIGHT_HEADED));
1124 | make_confused(HConfusion + d(2,4),FALSE);
1125 | } else if(!rn2(4) && !Blind) {
1126 | pline("Everything suddenly goes dark.");
1127 | make_blinded((long)d(2,10),FALSE);
1128 | } else if(!rn2(3)) {
1129 | const char *what, *where;
1130 | if (!Blind)
1131 | what = "goes", where = "dark";
1132 | else if (Levitation || Is_airlevel(&u.uz) ||
1133 | Is_waterlevel(&u.uz))
1134 | what = "you lose control of", where = "yourself";
1135 | else
1136 | what = "you slap against the", where = surface(u.ux,u.uy);
1137 | pline_The("world spins and %s %s.", what, where);
1138 | flags.soundok = 0;
1139 | nomul(-rnd(10));
1140 | nomovemsg = "You are conscious again.";
1141 | afternmv = Hear_again;
1142 | return(1);
1143 | }
1144 | return(0);
1145 | }
1146 |
1147 | STATIC_OVL int
1148 | eatcorpse(otmp) /* called when a corpse is selected as food */
1149 | register struct obj *otmp;
1150 | {
1151 | int tp = 0, mnum = otmp->corpsenm;
1152 | long rotted = 0L;
1153 | boolean uniq = !!(mons[mnum].geno & G_UNIQ);
1154 | int retcode = 0;
1155 | boolean stoneable = (touch_petrifies(&mons[mnum]) && !Stone_resistance &&
1156 | !poly_when_stoned(youmonst.data));
1157 |
1158 | if (mnum != PM_LIZARD && mnum != PM_LICHEN) {
1159 | long age = peek_at_iced_corpse_age(otmp);
1160 |
1161 | rotted = (monstermoves - age)/(10L + rn2(20));
1162 | if (otmp->cursed) rotted += 2L;
1163 | else if (otmp->blessed) rotted -= 2L;
1164 | }
1165 |
1166 | if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) {
1167 | pline("Ulch - that %s was tainted!",
1168 | mons[mnum].mlet == S_FUNGUS ? "fungoid vegetation" :
1169 | !vegetarian(&mons[mnum]) ? "meat" : "protoplasm");
1170 | if (Sick_resistance) {
1171 | pline("It doesn't seem at all sickening, though...");
1172 | } else {
1173 | char buf[BUFSZ];
1174 | long sick_time;
1175 |
1176 | sick_time = (long) rn1(10, 10);
1177 | /* make sure new ill doesn't result in improvement */
1178 | if (Sick && (sick_time > Sick))
1179 | sick_time = (Sick > 1L) ? Sick - 1L : 1L;
1180 | if (!uniq)
1181 | Sprintf(buf, "rotted %s", corpse_xname(otmp,TRUE));
1182 | else
1183 | Sprintf(buf, "%s%s rotted corpse",
1184 | !type_is_pname(&mons[mnum]) ? "the " : "",
1185 | s_suffix(mons[mnum].mname));
1186 | make_sick(sick_time, buf, TRUE, SICK_VOMITABLE);
1187 | }
1188 |
1189 | /* KMH, conduct */
1190 | if (!vegan(&mons[mnum]))
1191 | u.uconduct.unvegan++;
1192 | if (!vegetarian(&mons[mnum]))
1193 | violated_vegetarian();
1194 |
1195 | if (carried(otmp)) useup(otmp);
1196 | else useupf(otmp, 1L);
1197 | return(2);
1198 | } else if (acidic(&mons[mnum]) && !Acid_resistance) {
1199 | tp++;
1200 | You("have a very bad case of stomach acid.");
1201 | losehp(rnd(15), "acidic corpse", KILLED_BY_AN);
1202 | } else if (poisonous(&mons[mnum]) && rn2(5)) {
1203 | tp++;
1204 | pline("Ecch - that must have been poisonous!");
1205 | if(!Poison_resistance) {
1206 | losestr(rnd(4));
1207 | losehp(rnd(15), "poisonous corpse", KILLED_BY_AN);
1208 | } else You("seem unaffected by the poison.");
1209 | /* now any corpse left too long will make you mildly ill */
1210 | } else if ((rotted > 5L || (rotted > 3L && rn2(5)))
1211 | && !Sick_resistance) {
1212 | tp++;
1213 | You_feel("%ssick.", (Sick) ? "very " : "");
1214 | losehp(rnd(8), "cadaver", KILLED_BY_AN);
1215 | }
1216 |
1217 | /* delay is weight dependent */
1218 | victual.reqtime = 3 + (mons[mnum].cwt >> 6);
1219 |
1220 | if (!tp && mnum != PM_LIZARD && mnum != PM_LICHEN &&
1221 | (otmp->orotten || !rn2(7))) {
1222 | if (rottenfood(otmp)) {
1223 | otmp->orotten = TRUE;
1224 | (void)touchfood(otmp);
1225 | retcode = 1;
1226 | } else
1227 | otmp->oeaten >>= 2;
1228 | } else {
1229 | pline("%s%s %s!",
1230 | !uniq ? "This " : !type_is_pname(&mons[mnum]) ? "The " : "",
1231 | food_xname(otmp, FALSE),
1232 | (carnivorous(youmonst.data) && !herbivorous(youmonst.data)) ?
1233 | "is delicious" : "tastes terrible");
1234 | }
1235 |
1236 | /* KMH, conduct */
1237 | if (!vegan(&mons[mnum]))
1238 | u.uconduct.unvegan++;
1239 | if (!vegetarian(&mons[mnum]))
1240 | violated_vegetarian();
1241 |
1242 | return(retcode);
1243 | }
1244 |
1245 | STATIC_OVL void
1246 | start_eating(otmp) /* called as you start to eat */
1247 | register struct obj *otmp;
1248 | {
1249 | #ifdef DEBUG
1250 | debugpline("start_eating: %lx (victual = %lx)", otmp, victual.piece);
1251 | debugpline("reqtime = %d", victual.reqtime);
1252 | debugpline("(original reqtime = %d)", objects[otmp->otyp].oc_delay);
1253 | debugpline("nmod = %d", victual.nmod);
1254 | debugpline("oeaten = %d", otmp->oeaten);
1255 | #endif
1256 | victual.fullwarn = victual.doreset = FALSE;
1257 | victual.eating = TRUE;
1258 |
1259 | if (otmp->otyp == CORPSE) {
1260 | cprefx(victual.piece->corpsenm);
1261 | if (!victual.piece || !victual.eating) {
1262 | /* rider revived, or died and lifesaved */
1263 | return;
1264 | }
1265 | }
1266 |
1267 | if (bite()) return;
1268 |
1269 | if (++victual.usedtime >= victual.reqtime) {
1270 | /* print "finish eating" message if they just resumed -dlc */
1271 | done_eating(victual.reqtime > 1 ? TRUE : FALSE);
1272 | return;
1273 | }
1274 |
1275 | Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE));
1276 | set_occupation(eatfood, msgbuf, 0);
1277 | }
1278 |
1279 |
1280 | STATIC_OVL void
1281 | fprefx(otmp) /* called on "first bite" of (non-corpse) food */
1282 | struct obj *otmp;
1283 | {
1284 | switch(otmp->otyp) {
1285 | case FOOD_RATION:
1286 | if(u.uhunger <= 200)
1287 | if (Hallucination) pline("Oh wow, like, superior, man!");
1288 | else pline("That food really hit the spot!");
1289 | else if(u.uhunger <= 700) pline("That satiated your stomach!");
1290 | break;
1291 | case TRIPE_RATION:
1292 | if (carnivorous(youmonst.data) && !humanoid(youmonst.data))
1293 | pline("That tripe ration was surprisingly good!");
1294 | else {
1295 | pline("Yak - dog food!");
1296 | more_experienced(1,0);
1297 | flags.botl = 1;
1298 | }
1299 | if (rn2(2) &&
1300 | (Upolyd ? (!carnivorous(youmonst.data) ||
1301 | (humanoid(youmonst.data) &&
1302 | !is_orc(youmonst.data)))
1303 | : !CANNIBAL_ALLOWED())) {
1304 | make_vomiting((long)rn1(victual.reqtime, 14), FALSE);
1305 | }
1306 | break;
1307 | case MEATBALL:
1308 | case MEAT_STICK:
1309 | case HUGE_CHUNK_OF_MEAT:
1310 | case MEAT_RING:
1311 | goto give_feedback;
1312 | /* break; */
1313 | case CLOVE_OF_GARLIC:
1314 | if (is_undead(youmonst.data)) {
1315 | make_vomiting((long)rn1(victual.reqtime, 5), FALSE);
1316 | break;
1317 | }
1318 | /* Fall through otherwise */
1319 | default:
1320 | if (otmp->otyp==SLIME_MOLD && !otmp->cursed
1321 | && otmp->spe == current_fruit)
1322 | pline("My, that was a %s %s!",
1323 | Hallucination ? "primo" : "yummy",
1324 | singular(otmp, xname));
1325 | else
1326 | #ifdef UNIX
1327 | if (otmp->otyp == APPLE || otmp->otyp == PEAR) {
1328 | if (!Hallucination) pline("Core dumped.");
1329 | else {
1330 | /* This is based on an old Usenet joke, a fake a.out manual page */
1331 | int x = rnd(100);
1332 | if (x <= 75)
1333 | pline("Segmentation fault -- core dumped.");
1334 | else if (x <= 99)
1335 | pline("Bus error -- core dumped.");
1336 | else pline("Yo' mama -- core dumped.");
1337 | }
1338 | } else
1339 | #endif
1340 | #ifdef MAC /* KMH -- Why should Unix have all the fun? */
1341 | if (otmp->otyp == APPLE) {
1342 | pline("Delicious! Must be a Macintosh!");
1343 | } else
1344 | #endif
1345 | if (otmp->otyp == EGG && stale_egg(otmp)) {
1346 | pline("Ugh. Rotten egg."); /* perhaps others like it */
1347 | make_vomiting(Vomiting+d(10,4), TRUE);
1348 | } else
1349 | give_feedback:
1350 | pline("This %s is %s", singular(otmp, xname),
1351 | otmp->cursed ? (Hallucination ? "grody!" : "terrible!") :
1352 | (otmp->otyp == CRAM_RATION
1353 | || otmp->otyp == K_RATION
1354 | || otmp->otyp == C_RATION)
1355 | ? "bland." :
1356 | Hallucination ? "gnarly!" : "delicious!");
1357 | break;
1358 | }
1359 |
1360 | /* KMH, conduct */
1361 | switch (objects[otmp->otyp].oc_material) {
1362 | case WAX: /* let's assume bees' wax */
1363 | u.uconduct.unvegan++;
1364 | break;
1365 |
1366 | case FLESH:
1367 | if (otmp->otyp == EGG) {
1368 | u.uconduct.unvegan++;
1369 | break;
1370 | }
1371 | case LEATHER:
1372 | case BONE:
1373 | case DRAGON_HIDE:
1374 | u.uconduct.unvegan++;
1375 | violated_vegetarian();
1376 | break;
1377 |
1378 | default:
1379 | if (otmp->otyp == PANCAKE ||
1380 | otmp->otyp == FORTUNE_COOKIE || /* eggs */
1381 | otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR || /* milk */
1382 | otmp->otyp == LUMP_OF_ROYAL_JELLY)
1383 | u.uconduct.unvegan++;
1384 | break;
1385 | }
1386 | }
1387 |
1388 | STATIC_OVL void
1389 | eataccessory(otmp)
1390 | struct obj *otmp;
1391 | {
1392 | int typ = otmp->otyp;
1393 | int oldprop;
1394 |
1395 | /* Note: rings are not so common that this is unbalancing. */
1396 | /* (How often do you even _find_ 3 rings of polymorph in a game?) */
1397 | oldprop = !!(u.uprops[objects[typ].oc_oprop].intrinsic);
1398 | if (otmp == uleft || otmp == uright) {
1399 | Ring_gone(otmp);
1400 | if (u.uhp <= 0) return; /* died from sink fall */
1401 | }
1402 | otmp->known = otmp->dknown = 1; /* by taste */
1403 | if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5))
1404 | switch (otmp->otyp) {
1405 | default:
1406 | if (!objects[typ].oc_oprop) break; /* should never happen */
1407 |
1408 | if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE))
1409 | pline("Magic spreads through your body as you digest the %s.",
1410 | otmp->oclass == RING_CLASS ? "ring" : "amulet");
1411 |
1412 | u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE;
1413 |
1414 | switch (typ) {
1415 | case RIN_SEE_INVISIBLE:
1416 | set_mimic_blocking();
1417 | see_monsters();
1418 | if (Invis && !oldprop && !ESee_invisible &&
1419 | !perceives(youmonst.data) && !Blind) {
1420 | newsym(u.ux,u.uy);
1421 | pline("Suddenly you can see yourself.");
1422 | makeknown(typ);
1423 | }
1424 | break;
1425 | case RIN_INVISIBILITY:
1426 | if (!oldprop && !EInvis && !BInvis &&
1427 | !See_invisible && !Blind) {
1428 | newsym(u.ux,u.uy);
1429 | Your("body takes on a %s transparency...",
1430 | Hallucination ? "normal" : "strange");
1431 | makeknown(typ);
1432 | }
1433 | break;
1434 | case RIN_PROTECTION_FROM_SHAPE_CHAN:
1435 | rescham();
1436 | break;
1437 | case RIN_LEVITATION:
1438 | if (!Levitation) {
1439 | float_up();
1440 | incr_itimeout(&HLevitation, d(10,20));
1441 | makeknown(typ);
1442 | }
1443 | break;
1444 | }
1445 | break;
1446 | case RIN_ADORNMENT:
1447 | if (adjattrib(A_CHA, otmp->spe, -1))
1448 | makeknown(typ);
1449 | break;
1450 | case RIN_GAIN_STRENGTH:
1451 | if (adjattrib(A_STR, otmp->spe, -1))
1452 | makeknown(typ);
1453 | break;
1454 | case RIN_GAIN_CONSTITUTION:
1455 | if (adjattrib(A_CON, otmp->spe, -1))
1456 | makeknown(typ);
1457 | break;
1458 | case RIN_INCREASE_ACCURACY:
1459 | u.uhitinc += otmp->spe;
1460 | break;
1461 | case RIN_INCREASE_DAMAGE:
1462 | u.udaminc += otmp->spe;
1463 | break;
1464 | case RIN_PROTECTION:
1465 | HProtection |= FROMOUTSIDE;
1466 | u.ublessed += otmp->spe;
1467 | flags.botl = 1;
1468 | break;
1469 | case RIN_FREE_ACTION:
1470 | /* Give sleep resistance instead */
1471 | if (!Sleep_resistance)
1472 | You_feel("wide awake.");
1473 | HSleep_resistance |= FROMOUTSIDE;
1474 | break;
1475 | case AMULET_OF_CHANGE:
1476 | makeknown(typ);
1477 | change_sex();
1478 | You("are suddenly very %s!",
1479 | flags.female ? "feminine" : "masculine");
1480 | flags.botl = 1;
1481 | break;
1482 | case AMULET_OF_STRANGULATION: /* bad idea! */
1483 | choke(otmp);
1484 | break;
1485 | case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */
1486 | HSleeping = FROMOUTSIDE | rnd(100);
1487 | break;
1488 | case RIN_SUSTAIN_ABILITY:
1489 | case AMULET_OF_LIFE_SAVING:
1490 | case AMULET_OF_REFLECTION: /* nice try */
1491 | /* can't eat Amulet of Yendor or fakes,
1492 | * and no oc_prop even if you could -3.
1493 | */
1494 | break;
1495 | }
1496 | }
1497 |
1498 | STATIC_OVL void
1499 | eatspecial() /* called after eating non-food */
1500 | {
1501 | register struct obj *otmp = victual.piece;
1502 |
1503 | lesshungry(victual.nmod);
1504 | victual.piece = (struct obj *)0;
1505 | victual.eating = 0;
1506 | if (otmp->oclass == GOLD_CLASS) {
1507 | dealloc_obj(otmp);
1508 | return;
1509 | }
1510 | if (otmp->oclass == POTION_CLASS) {
1511 | otmp->quan++; /* dopotion() does a useup() */
1512 | (void)dopotion(otmp);
1513 | }
1514 | if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS)
1515 | eataccessory(otmp);
1516 | else if (otmp->otyp == LEASH && otmp->leashmon)
1517 | o_unleash(otmp);
1518 |
1519 | /* KMH -- idea by "Tommy the Terrorist" */
1520 | if ((otmp->otyp == TRIDENT) && !otmp->cursed)
1521 | {
1522 | pline(Hallucination ? "Four out of five dentists agree." :
1523 | "That was pure chewing satisfaction!");
1524 | exercise(A_WIS, TRUE);
1525 | }
1526 | if ((otmp->otyp == FLINT) && !otmp->cursed)
1527 | {
1528 | pline("Yabba-dabba delicious!");
1529 | exercise(A_CON, TRUE);
1530 | }
1531 |
1532 | if (otmp == uwep && otmp->quan == 1L) uwepgone();
1533 | if (otmp == uquiver && otmp->quan == 1L) uqwepgone();
1534 | if (otmp == uswapwep && otmp->quan == 1L) uswapwepgone();
1535 |
1536 | if (otmp == uball) unpunish();
1537 | if (otmp == uchain) unpunish(); /* but no useup() */
1538 | else if (carried(otmp)) useup(otmp);
1539 | else useupf(otmp, 1L);
1540 | }
1541 |
1542 | /* NOTE: the order of these words exactly corresponds to the
1543 | order of oc_material values #define'd in objclass.h. */
1544 | static const char *foodwords[] = {
1545 | "meal", "liquid", "wax", "food", "meat",
1546 | "paper", "cloth", "leather", "wood", "bone", "scale",
1547 | "metal", "metal", "metal", "silver", "gold", "platinum", "mithril",
1548 | "plastic", "glass", "rich food", "stone"
1549 | };
1550 |
1551 | STATIC_OVL const char *
1552 | foodword(otmp)
1553 | register struct obj *otmp;
1554 | {
1555 | if (otmp->oclass == FOOD_CLASS) return "food";
1556 | if (otmp->oclass == GEM_CLASS &&
1557 | objects[otmp->otyp].oc_material == GLASS &&
1558 | otmp->dknown)
1559 | makeknown(otmp->otyp);
1560 | return foodwords[objects[otmp->otyp].oc_material];
1561 | }
1562 |
1563 | STATIC_OVL void
1564 | fpostfx(otmp) /* called after consuming (non-corpse) food */
1565 | register struct obj *otmp;
1566 | {
1567 | switch(otmp->otyp) {
1568 | case SPRIG_OF_WOLFSBANE:
1569 | if (u.ulycn >= LOW_PM || is_were(youmonst.data))
1570 | you_unwere(TRUE);
1571 | break;
1572 | case CARROT:
1573 | make_blinded(0L,TRUE);
1574 | break;
1575 | case FORTUNE_COOKIE:
1576 | outrumor(bcsign(otmp), BY_COOKIE);
1577 | if (!Blind) u.uconduct.literate++;
1578 | break;
1579 | case LUMP_OF_ROYAL_JELLY:
1580 | /* This stuff seems to be VERY healthy! */
1581 | gainstr(otmp, 1);
1582 | if (Upolyd) {
1583 | u.mh += otmp->cursed ? -rnd(20) : rnd(20);
1584 | if (u.mh > u.mhmax) {
1585 | if (!rn2(17)) u.mhmax++;
1586 | u.mh = u.mhmax;
1587 | } else if (u.mh <= 0) {
1588 | rehumanize();
1589 | }
1590 | } else {
1591 | u.uhp += otmp->cursed ? -rnd(20) : rnd(20);
1592 | if (u.uhp > u.uhpmax) {
1593 | if(!rn2(17)) u.uhpmax++;
1594 | u.uhp = u.uhpmax;
1595 | } else if (u.uhp <= 0) {
1596 | killer_format = KILLED_BY_AN;
1597 | killer = "rotten lump of royal jelly";
1598 | done(POISONING);
1599 | }
1600 | }
1601 | if(!otmp->cursed) heal_legs();
1602 | break;
1603 | case EGG:
1604 | if (touch_petrifies(&mons[otmp->corpsenm])) {
1605 | if (!Stone_resistance &&
1606 | !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
1607 | if (!Stoned) Stoned = 5;
1608 | killer_format = KILLED_BY_AN;
1609 | Sprintf(killer_buf, "%s egg", mons[otmp->corpsenm].mname);
1610 | delayed_killer = killer_buf;
1611 | }
1612 | }
1613 | break;
1614 | case EUCALYPTUS_LEAF:
1615 | if (Sick && !otmp->cursed)
1616 | make_sick(0L, (char *)0, TRUE, SICK_ALL);
1617 | if (Vomiting && !otmp->cursed)
1618 | make_vomiting(0L, TRUE);
1619 | break;
1620 | }
1621 | return;
1622 | }
1623 |
1624 | int
1625 | doeat() /* generic "eat" command funtion (see cmd.c) */
1626 | {
1627 | register struct obj *otmp;
1628 | int basenutrit; /* nutrition of full item */
1629 | boolean dont_start = FALSE;
1630 |
1631 | if (Strangled) {
1632 | pline("If you can't breathe air, how can you consume solids?");
1633 | return 0;
1634 | }
1635 | if (!(otmp = floorfood("eat", 0))) return 0;
1636 | if (check_capacity((char *)0)) return 0;
1637 |
1638 | /* We have to make non-foods take 1 move to eat, unless we want to
1639 | * do ridiculous amounts of coding to deal with partly eaten plate
1640 | * mails, players who polymorph back to human in the middle of their
1641 | * metallic meal, etc....
1642 | */
1643 | if (!is_edible(otmp)) {
1644 | You("cannot eat that!");
1645 | return 0;
1646 | } else if ((otmp->owornmask & (W_ARMOR|W_TOOL|W_AMUL
1647 | #ifdef STEED
1648 | |W_SADDLE
1649 | #endif
1650 | )) != 0) {
1651 | /* let them eat rings */
1652 | You_cant("eat %s you're wearing.", something);
1653 | return 0;
1654 | }
1655 | if (is_metallic(otmp) &&
1656 | u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) {
1657 | otmp->rknown = TRUE;
1658 | if (otmp->quan > 1L) {
1659 | if(!carried(otmp))
1660 | (void) splitobj(otmp, 1L);
1661 | else
1662 | otmp = splitobj(otmp, otmp->quan - 1L);
1663 | }
1664 | pline("Ulch - That %s was rustproofed!", xname(otmp));
1665 | /* The regurgitated object's rustproofing is gone now */
1666 | otmp->oerodeproof = 0;
1667 | make_stunned(HStun + rn2(10), TRUE);
1668 | You("spit %s out onto the %s.", the(xname(otmp)),
1669 | surface(u.ux, u.uy));
1670 | if (carried(otmp)) {
1671 | freeinv(otmp);
1672 | dropy(otmp);
1673 | }
1674 | stackobj(otmp);
1675 | return 1;
1676 | }
1677 | /* KMH -- Slow digestion is... undigestable */
1678 | if (otmp->otyp == RIN_SLOW_DIGESTION) {
1679 | pline("This ring is undigestable!");
1680 | (void) rottenfood(otmp);
1681 | if (otmp->dknown && !objects[otmp->otyp].oc_name_known
1682 | && !objects[otmp->otyp].oc_uname)
1683 | docall(otmp);
1684 | return (1);
1685 | }
1686 | if (otmp->oclass != FOOD_CLASS) {
1687 | victual.reqtime = 1;
1688 | victual.piece = otmp;
1689 | /* Don't split it, we don't need to if it's 1 move */
1690 | victual.usedtime = 0;
1691 | victual.canchoke = (u.uhs == SATIATED);
1692 | /* Note: gold weighs 1 pt. for each 1000 pieces (see */
1693 | /* pickup.c) so gold and non-gold is consistent. */
1694 | if (otmp->oclass == GOLD_CLASS)
1695 | basenutrit = ((otmp->quan > 200000L) ? 2000
1696 | : (int)(otmp->quan/100L));
1697 | else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS)
1698 | basenutrit = weight(otmp);
1699 | /* oc_nutrition is usually weight anyway */
1700 | else basenutrit = objects[otmp->otyp].oc_nutrition;
1701 | victual.nmod = basenutrit;
1702 | victual.eating = TRUE; /* needed for lesshungry() */
1703 |
1704 | if (otmp->cursed)
1705 | (void) rottenfood(otmp);
1706 |
1707 | if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) {
1708 | pline("Ecch - that must have been poisonous!");
1709 | if(!Poison_resistance) {
1710 | losestr(rnd(4));
1711 | losehp(rnd(15), xname(otmp), KILLED_BY_AN);
1712 | } else
1713 | You("seem unaffected by the poison.");
1714 | } else if (!otmp->cursed)
1715 | pline("This %s is delicious!",
1716 | otmp->oclass == GOLD_CLASS ? foodword(otmp) :
1717 | singular(otmp, xname));
1718 |
1719 | u.uconduct.food++;
1720 | eatspecial();
1721 | return 1;
1722 | }
1723 |
1724 | if(otmp == victual.piece) {
1725 | /* If they weren't able to choke, they don't suddenly become able to
1726 | * choke just because they were interrupted. On the other hand, if
1727 | * they were able to choke before, if they lost food it's possible
1728 | * they shouldn't be able to choke now.
1729 | */
1730 | if (u.uhs != SATIATED) victual.canchoke = FALSE;
1731 | if(!carried(victual.piece)) {
1732 | if(victual.piece->quan > 1L)
1733 | (void) splitobj(victual.piece, 1L);
1734 | }
1735 | You("resume your meal.");
1736 | start_eating(victual.piece);
1737 | return(1);
1738 | }
1739 |
1740 | /* nothing in progress - so try to find something. */
1741 | /* tins are a special case */
1742 | /* tins must also check conduct separately in case they're discarded */
1743 | if(otmp->otyp == TIN) {
1744 | start_tin(otmp);
1745 | return(1);
1746 | }
1747 |
1748 | /* KMH, conduct */
1749 | u.uconduct.food++;
1750 |
1751 | victual.piece = otmp = touchfood(otmp);
1752 | victual.usedtime = 0;
1753 |
1754 | /* Now we need to calculate delay and nutritional info.
1755 | * The base nutrition calculated here and in eatcorpse() accounts
1756 | * for normal vs. rotten food. The reqtime and nutrit values are
1757 | * then adjusted in accordance with the amount of food left.
1758 | */
1759 | if(otmp->otyp == CORPSE) {
1760 | int tmp = eatcorpse(otmp);
1761 | if (tmp == 2) {
1762 | /* used up */
1763 | victual.piece = (struct obj *)0;
1764 | return(1);
1765 | } else if (tmp)
1766 | dont_start = TRUE;
1767 | /* if not used up, eatcorpse sets up reqtime and may modify
1768 | * oeaten */
1769 | } else {
1770 | victual.reqtime = objects[otmp->otyp].oc_delay;
1771 | if (otmp->otyp != FORTUNE_COOKIE &&
1772 | (otmp->cursed ||
1773 | (((monstermoves - otmp->age) > (int) otmp->blessed ? 50:30) &&
1774 | (otmp->orotten || !rn2(7))))) {
1775 |
1776 | if (rottenfood(otmp)) {
1777 | otmp->orotten = TRUE;
1778 | dont_start = TRUE;
1779 | }
1780 | otmp->oeaten >>= 1;
1781 | } else fprefx(otmp);
1782 | }
1783 |
1784 | /* re-calc the nutrition */
1785 | if (otmp->otyp == CORPSE) basenutrit = mons[otmp->corpsenm].cnutrit;
1786 | else basenutrit = objects[otmp->otyp].oc_nutrition;
1787 |
1788 | #ifdef DEBUG
1789 | debugpline("before rounddiv: victual.reqtime == %d", victual.reqtime);
1790 | debugpline("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit);
1791 | #endif
1792 | victual.reqtime = (basenutrit == 0 ? 0 :
1793 | rounddiv(victual.reqtime * (long)otmp->oeaten, basenutrit));
1794 | #ifdef DEBUG
1795 | debugpline("after rounddiv: victual.reqtime == %d", victual.reqtime);
1796 | #endif
1797 | /* calculate the modulo value (nutrit. units per round eating)
1798 | * note: this isn't exact - you actually lose a little nutrition
1799 | * due to this method.
1800 | * TODO: add in a "remainder" value to be given at the end of the
1801 | * meal.
1802 | */
1803 | if (victual.reqtime == 0 || otmp->oeaten == 0)
1804 | /* possible if most has been eaten before */
1805 | victual.nmod = 0;
1806 | else if ((int)otmp->oeaten >= victual.reqtime)
1807 | victual.nmod = -((int)otmp->oeaten / victual.reqtime);
1808 | else
1809 | victual.nmod = victual.reqtime % otmp->oeaten;
1810 | victual.canchoke = (u.uhs == SATIATED);
1811 |
1812 | if (!dont_start) start_eating(otmp);
1813 | return(1);
1814 | }
1815 |
1816 | /* Take a single bite from a piece of food, checking for choking and
1817 | * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise.
1818 | */
1819 | STATIC_OVL int
1820 | bite()
1821 | {
1822 | if(victual.canchoke && u.uhunger >= 2000) {
1823 | choke(victual.piece);
1824 | return 1;
1825 | }
1826 | if (victual.doreset) {
1827 | do_reset_eat();
1828 | return 0;
1829 | }
1830 | force_save_hs = TRUE;
1831 | if(victual.nmod < 0) {
1832 | lesshungry(-victual.nmod);
1833 | victual.piece->oeaten -= -victual.nmod;
1834 | } else if(victual.nmod > 0 && (victual.usedtime % victual.nmod)) {
1835 | lesshungry(1);
1836 | victual.piece->oeaten--;
1837 | }
1838 | force_save_hs = FALSE;
1839 | recalc_wt();
1840 | return 0;
1841 | }
1842 |
1843 | #endif /* OVLB */
1844 | #ifdef OVL0
1845 |
1846 | void
1847 | gethungry() /* as time goes by - called by moveloop() and domove() */
1848 | {
1849 | if (u.uinvulnerable) return; /* you don't feel hungrier */
1850 |
1851 | if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */
1852 | && (carnivorous(youmonst.data) || herbivorous(youmonst.data))
1853 | && !Slow_digestion)
1854 | u.uhunger--; /* ordinary food consumption */
1855 |
1856 | if (moves % 2) { /* odd turns */
1857 | /* Regeneration uses up food, unless due to an artifact */
1858 | if (HRegeneration || ((ERegeneration & (~W_ART)) &&
1859 | (ERegeneration != W_WEP || !uwep->oartifact)))
1860 | u.uhunger--;
1861 | if (near_capacity() > SLT_ENCUMBER) u.uhunger--;
1862 | } else { /* even turns */
1863 | if (Hunger) u.uhunger--;
1864 | /* Conflict uses up food too */
1865 | if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--;
1866 | /* +0 charged rings don't do anything, so don't affect hunger */
1867 | /* Slow digestion still uses ring hunger */
1868 | switch ((int)(moves % 20)) { /* note: use even cases only */
1869 | case 4: if (uleft &&
1870 | (uleft->spe || !objects[uleft->otyp].oc_charged))
1871 | u.uhunger--;
1872 | break;
1873 | case 8: if (uamul) u.uhunger--;
1874 | break;
1875 | case 12: if (uright &&
1876 | (uright->spe || !objects[uright->otyp].oc_charged))
1877 | u.uhunger--;
1878 | break;
1879 | case 16: if (u.uhave.amulet) u.uhunger--;
1880 | break;
1881 | default: break;
1882 | }
1883 | }
1884 | newuhs(TRUE);
1885 | }
1886 |
1887 | #endif /* OVL0 */
1888 | #ifdef OVLB
1889 |
1890 | void
1891 | morehungry(num) /* called after vomiting and after performing feats of magic */
1892 | register int num;
1893 | {
1894 | u.uhunger -= num;
1895 | newuhs(TRUE);
1896 | }
1897 |
1898 |
1899 | void
1900 | lesshungry(num) /* called after eating (and after drinking fruit juice) */
1901 | register int num;
1902 | {
1903 | #ifdef DEBUG
1904 | debugpline("lesshungry(%d)", num);
1905 | #endif
1906 | u.uhunger += num;
1907 | if(u.uhunger >= 2000) {
1908 | if (!victual.eating || victual.canchoke) {
1909 | if (victual.eating) {
1910 | choke(victual.piece);
1911 | reset_eat();
1912 | } else
1913 | choke(tin.tin); /* may be null */
1914 | /* no reset_eat() */
1915 | }
1916 | } else {
1917 | /* Have lesshungry() report when you're nearly full so all eating
1918 | * warns when you're about to choke.
1919 | */
1920 | if (u.uhunger >= 1500) {
1921 | if (!victual.eating || (victual.eating && !victual.fullwarn)) {
1922 | pline("You're having a hard time getting all of it down.");
1923 | nomovemsg = "You're finally finished.";
1924 | if (!victual.eating)
1925 | multi = -2;
1926 | else {
1927 | victual.fullwarn = TRUE;
1928 | if (victual.canchoke && victual.reqtime > 1) {
1929 | /* a one-gulp food will not survive a stop */
1930 | if (yn_function("Stop eating?",ynchars,'y')=='y') {
1931 | reset_eat();
1932 | nomovemsg = (char *)0;
1933 | }
1934 | }
1935 | }
1936 | }
1937 | }
1938 | }
1939 | newuhs(FALSE);
1940 | }
1941 |
1942 | STATIC_PTR
1943 | int
1944 | unfaint()
1945 | {
1946 | (void) Hear_again();
1947 | if(u.uhs > FAINTING)
1948 | u.uhs = FAINTING;
1949 | stop_occupation();
1950 | flags.botl = 1;
1951 | return 0;
1952 | }
1953 |
1954 | #endif /* OVLB */
1955 | #ifdef OVL0
1956 |
1957 | boolean
1958 | is_fainted()
1959 | {
1960 | return((boolean)(u.uhs == FAINTED));
1961 | }
1962 |
1963 | void
1964 | reset_faint() /* call when a faint must be prematurely terminated */
1965 | {
1966 | if(is_fainted()) nomul(0);
1967 | }
1968 |
1969 | #if 0
1970 | void
1971 | sync_hunger()
1972 | {
1973 |
1974 | if(is_fainted()) {
1975 |
1976 | flags.soundok = 0;
1977 | nomul(-10+(u.uhunger/10));
1978 | nomovemsg = "You regain consciousness.";
1979 | afternmv = unfaint;
1980 | }
1981 | }
1982 | #endif
1983 |
1984 | void
1985 | newuhs(incr) /* compute and comment on your (new?) hunger status */
1986 | boolean incr;
1987 | {
1988 | unsigned newhs;
1989 | static unsigned save_hs;
1990 | static boolean saved_hs = FALSE;
1991 | int h = u.uhunger;
1992 |
1993 | newhs = (h > 1000) ? SATIATED :
1994 | (h > 150) ? NOT_HUNGRY :
1995 | (h > 50) ? HUNGRY :
1996 | (h > 0) ? WEAK : FAINTING;
1997 |
1998 | /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY.
1999 | * This should not produce the message "you only feel hungry now";
2000 | * that message should only appear if HUNGRY is an endpoint. Therefore
2001 | * we check to see if we're in the middle of eating. If so, we save
2002 | * the first hunger status, and at the end of eating we decide what
2003 | * message to print based on the _entire_ meal, not on each little bit.
2004 | */
2005 | /* It is normally possible to check if you are in the middle of a meal
2006 | * by checking occupation == eatfood, but there is one special case:
2007 | * start_eating() can call bite() for your first bite before it
2008 | * sets the occupation.
2009 | * Anyone who wants to get that case to work _without_ an ugly static
2010 | * force_save_hs variable, feel free.
2011 | */
2012 | /* Note: If you become a certain hunger status in the middle of the
2013 | * meal, and still have that same status at the end of the meal,
2014 | * this will incorrectly print the associated message at the end of
2015 | * the meal instead of the middle. Such a case is currently
2016 | * impossible, but could become possible if a message for SATIATED
2017 | * were added or if HUNGRY and WEAK were separated by a big enough
2018 | * gap to fit two bites.
2019 | */
2020 | if (occupation == eatfood || force_save_hs) {
2021 | if (!saved_hs) {
2022 | save_hs = u.uhs;
2023 | saved_hs = TRUE;
2024 | }
2025 | u.uhs = newhs;
2026 | return;
2027 | } else {
2028 | if (saved_hs) {
2029 | u.uhs = save_hs;
2030 | saved_hs = FALSE;
2031 | }
2032 | }
2033 |
2034 | if(newhs == FAINTING) {
2035 | if(is_fainted()) newhs = FAINTED;
2036 | if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) {
2037 | if(!is_fainted() && multi >= 0 /* %% */) {
2038 | /* stop what you're doing, then faint */
2039 | stop_occupation();
2040 | You("faint from lack of food.");
2041 | flags.soundok = 0;
2042 | nomul(-10+(u.uhunger/10));
2043 | nomovemsg = "You regain consciousness.";
2044 | afternmv = unfaint;
2045 | newhs = FAINTED;
2046 | }
2047 | } else
2048 | if(u.uhunger < -(int)(200 + 20*ACURR(A_CON))) {
2049 | u.uhs = STARVED;
2050 | flags.botl = 1;
2051 | bot();
2052 | You("die from starvation.");
2053 | killer_format = KILLED_BY;
2054 | killer = "starvation";
2055 | done(STARVING);
2056 | /* if we return, we lifesaved, and that calls newuhs */
2057 | return;
2058 | }
2059 | }
2060 |
2061 | if(newhs != u.uhs) {
2062 | if(newhs >= WEAK && u.uhs < WEAK)
2063 | losestr(1); /* this may kill you -- see below */
2064 | else if(newhs < WEAK && u.uhs >= WEAK)
2065 | losestr(-1);
2066 | switch(newhs){
2067 | case HUNGRY:
2068 | if (Hallucination) {
2069 | You((!incr) ?
2070 | "now have a lesser case of the munchies." :
2071 | "are getting the munchies.");
2072 | } else
2073 | You((!incr) ? "only feel hungry now." :
2074 | (u.uhunger < 145) ? "feel hungry." :
2075 | "are beginning to feel hungry.");
2076 | if (incr && occupation &&
2077 | (occupation != eatfood && occupation != opentin))
2078 | stop_occupation();
2079 | break;
2080 | case WEAK:
2081 | if (Hallucination)
2082 | pline((!incr) ?
2083 | "You still have the munchies." :
2084 | "The munchies are interfering with your motor capabilities.");
2085 | else if (incr &&
2086 | (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)))
2087 | pline("%s needs food, badly!",
2088 | (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ?
2089 | urole.name.m : "Elf");
2090 | else
2091 | You((!incr) ? "feel weak now." :
2092 | (u.uhunger < 45) ? "feel weak." :
2093 | "are beginning to feel weak.");
2094 | if (incr && occupation &&
2095 | (occupation != eatfood && occupation != opentin))
2096 | stop_occupation();
2097 | break;
2098 | }
2099 | u.uhs = newhs;
2100 | flags.botl = 1;
2101 | bot();
2102 | if ((Upolyd ? u.mh : u.uhp) < 1) {
2103 | You("die from hunger and exhaustion.");
2104 | killer_format = KILLED_BY;
2105 | killer = "exhaustion";
2106 | done(STARVING);
2107 | return;
2108 | }
2109 | }
2110 | }
2111 |
2112 | #endif /* OVL0 */
2113 | #ifdef OVLB
2114 |
2115 | /* Returns an object representing food. Object may be either on floor or
2116 | * in inventory.
2117 | */
2118 | struct obj *
2119 | floorfood(verb,corpsecheck) /* get food from floor or pack */
2120 | const char *verb;
2121 | int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */
2122 | {
2123 | register struct obj *otmp;
2124 | char qbuf[QBUFSZ];
2125 | char c;
2126 | boolean feeding = (!strcmp(verb, "eat"));
2127 |
2128 | if (feeding && metallivorous(youmonst.data)) {
2129 | struct obj *gold;
2130 | struct trap *ttmp = t_at(u.ux, u.uy);
2131 |
2132 | if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) {
2133 | /* If not already stuck in the trap, perhaps there should
2134 | be a chance to becoming trapped? Probably not, because
2135 | then the trap would just get eaten on the _next_ turn... */
2136 | Sprintf(qbuf, "There is a bear trap here (%s); eat it?",
2137 | (u.utrap && u.utraptype == TT_BEARTRAP) ?
2138 | "holding you" : "armed");
2139 | if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2140 | u.utrap = u.utraptype = 0;
2141 | deltrap(ttmp);
2142 | return mksobj(BEARTRAP, TRUE, FALSE);
2143 | } else if (c == 'q') {
2144 | return (struct obj *)0;
2145 | }
2146 | }
2147 |
2148 | if (
2149 | #ifdef STEED
2150 | !u.usteed &&
2151 | #endif
2152 | (gold = g_at(u.ux, u.uy)) != 0) {
2153 | if (gold->quan == 1L)
2154 | Sprintf(qbuf, "There is 1 gold piece here; eat it?");
2155 | else
2156 | Sprintf(qbuf, "There are %ld gold pieces here; eat them?",
2157 | gold->quan);
2158 | if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') {
2159 | obj_extract_self(gold);
2160 | return gold;
2161 | } else if (c == 'q') {
2162 | return (struct obj *)0;
2163 | }
2164 | }
2165 | }
2166 |
2167 | /* Is there some food (probably a heavy corpse) here on the ground? */
2168 | if (
2169 | #ifdef STEED
2170 | !u.usteed &&
2171 | #endif
2172 | !(Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz))
2173 | && !u.uswallow) {
2174 | for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) {
2175 | if(corpsecheck ?
2176 | (otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) :
2177 | feeding ? (otmp->oclass != GOLD_CLASS && is_edible(otmp)) :
2178 | otmp->oclass==FOOD_CLASS) {
2179 | Sprintf(qbuf, "There %s %s here; %s %s?",
2180 | (otmp->quan == 1L) ? "is" : "are",
2181 | doname(otmp), verb,
2182 | (otmp->quan == 1L) ? "it" : "one");
2183 | if((c = yn_function(qbuf,ynqchars,'n')) == 'y')
2184 | return(otmp);
2185 | else if(c == 'q')
2186 | return((struct obj *) 0);
2187 | }
2188 | }
2189 | }
2190 | /* We cannot use ALL_CLASSES since that causes getobj() to skip its
2191 | * "ugly checks" and we need to check for inedible items.
2192 | */
2193 | otmp = getobj(feeding ? (const char *)allobj :
2194 | (const char *)comestibles, verb);
2195 | if (corpsecheck && otmp)
2196 | if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) {
2197 | You_cant("%s that!", verb);
2198 | return (struct obj *)0;
2199 | }
2200 | return otmp;
2201 | }
2202 |
2203 | /* Side effects of vomiting */
2204 | /* added nomul (MRS) - it makes sense, you're too busy being sick! */
2205 | void
2206 | vomit() /* A good idea from David Neves */
2207 | {
2208 | make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE);
2209 | nomul(-2);
2210 | }
2211 |
2212 | int
2213 | eaten_stat(base, obj)
2214 | register int base;
2215 | register struct obj *obj;
2216 | {
2217 | long uneaten_amt, full_amount;
2218 |
2219 | uneaten_amt = (long)obj->oeaten;
2220 | full_amount = (obj->otyp == CORPSE) ? (long)mons[obj->corpsenm].cnutrit
2221 | : (long)objects[obj->otyp].oc_nutrition;
2222 |
2223 | base = (int)(full_amount ? (long)base * uneaten_amt / full_amount : 0L);
2224 | return (base < 1) ? 1 : base;
2225 | }
2226 |
2227 | #endif /* OVLB */
2228 |
2229 | /*eat.c*/