installer - Several improvements
[dragonfly.git] / games / hack / hack.eat.c
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.eat.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.eat.c,v 1.4 1999/11/16 10:26:36 marcel Exp $ */
4
5 #include "hack.h"
6 char POISONOUS[] = "ADKSVabhks";
7
8 static bool     opentin(void);
9 static void     Meatdone(void);
10 static void     unfaint(void);
11 static void     newuhs(bool);
12 static int      eatcorpse(struct obj *);
13
14 /* hunger texts used on bottom line (each 8 chars long) */
15 #define SATIATED        0
16 #define NOT_HUNGRY      1
17 #define HUNGRY          2
18 #define WEAK            3
19 #define FAINTING        4
20 #define FAINTED         5
21 #define STARVED         6
22
23 const char *hu_stat[] = {
24         "Satiated",
25         "        ",
26         "Hungry  ",
27         "Weak    ",
28         "Fainting",
29         "Fainted ",
30         "Starved "
31 };
32
33 void
34 init_uhunger(void)
35 {
36         u.uhunger = 900;
37         u.uhs = NOT_HUNGRY;
38 }
39
40 #define TTSZ    SIZE(tintxts)
41 struct { const char *txt; int nut; } tintxts[] = {
42         { "It contains first quality peaches - what a surprise!", 40 },
43         { "It contains salmon - not bad!", 60 },
44         { "It contains apple juice - perhaps not what you hoped for.", 20 },
45         { "It contains some nondescript substance, tasting awfully.", 500 },
46         { "It contains rotten meat. You vomit.", -50 },
47         { "It turns out to be empty.", 0 }
48 };
49
50 static struct {
51         struct obj *tin;
52         int usedtime, reqtime;
53 } tin;
54
55 static bool
56 opentin(void)
57 {
58         int r;
59
60         if (!carried(tin.tin))  /* perhaps it was stolen? */
61                 return (0);     /* %% probably we should use tinoid */
62         if (tin.usedtime++ >= 50) {
63                 pline("You give up your attempt to open the tin.");
64                 return (0);
65         }
66         if (tin.usedtime < tin.reqtime)
67                 return (1);     /* still busy */
68
69         pline("You succeed in opening the tin.");
70         useup(tin.tin);
71         r = rn2(2 * TTSZ);
72         if (r < TTSZ) {
73                 pline("%s", tintxts[r].txt);
74                 lesshungry(tintxts[r].nut);
75                 if (r == 1) {   /* SALMON */
76                         Glib = rnd(15);
77                         pline("Eating salmon made your fingers very slippery.");
78                 }
79         } else {
80                 pline("It contains spinach - this makes you feel like Popeye!");
81                 lesshungry(600);
82                 if (u.ustr < 118)
83                         u.ustr += rnd(((u.ustr < 17) ? 19 : 118) - u.ustr);
84                 if (u.ustr > u.ustrmax)
85                         u.ustrmax = u.ustr;
86                 flags.botl = 1;
87         }
88         return (0);
89 }
90
91 static void
92 Meatdone(void)
93 {
94         u.usym = '@';
95         prme();
96 }
97
98 int
99 doeat(void)
100 {
101         struct obj *otmp;
102         struct objclass *ftmp;
103         int tmp;
104
105         /* Is there some food (probably a heavy corpse) here on the ground? */
106         if (!Levitation)
107                 for (otmp = fobj; otmp; otmp = otmp->nobj) {
108                         if (otmp->ox == u.ux && otmp->oy == u.uy &&
109                             otmp->olet == FOOD_SYM) {
110                                 pline("There %s %s here; eat %s? [ny] ",
111                                       (otmp->quan == 1) ? "is" : "are",
112                                       doname(otmp),
113                                       (otmp->quan == 1) ? "it" : "one");
114                                 if (readchar() == 'y') {
115                                         if (otmp->quan != 1)
116                                                 splitobj(otmp, 1);
117                                         freeobj(otmp);
118                                         otmp = addinv(otmp);
119                                         addtobill(otmp);
120                                         goto gotit;
121                                 }
122                         }
123                 }
124
125         otmp = getobj("%", "eat");
126         if (!otmp)
127                 return (0);
128 gotit:
129         if (otmp->otyp == TIN) {
130                 if (uwep) {
131                         switch (uwep->otyp) {
132                         case CAN_OPENER:
133                                 tmp = 1;
134                                 break;
135                         case DAGGER:
136                         case CRYSKNIFE:
137                                 tmp = 3;
138                                 break;
139                         case PICK_AXE:
140                         case AXE:
141                                 tmp = 6;
142                                 break;
143                         default:
144                                 goto no_opener;
145                         }
146                         pline("Using your %s you try to open the tin.",
147                               aobjnam(uwep, NULL));
148                 } else {
149 no_opener:
150                         pline("It is not so easy to open this tin.");
151                         if (Glib) {
152                                 pline("The tin slips out of your hands.");
153                                 if (otmp->quan > 1) {
154                                         struct obj *obj;
155
156                                         obj = splitobj(otmp, 1);
157                                         if (otmp == uwep)
158                                                 setuwep(obj);
159                                 }
160                                 dropx(otmp);
161                                 return (1);
162                         }
163                         tmp = 10 + rn2(1 + 500 / ((int)(u.ulevel + u.ustr)));
164                 }
165                 tin.reqtime = tmp;
166                 tin.usedtime = 0;
167                 tin.tin = otmp;
168                 occupation = opentin;
169                 occtxt = "opening the tin";
170                 return (1);
171         }
172         ftmp = &objects[otmp->otyp];
173         multi = -ftmp->oc_delay;
174         if (otmp->otyp >= CORPSE && eatcorpse(otmp))
175                 goto eatx;
176         if (!rn2(7) && otmp->otyp != FORTUNE_COOKIE) {
177                 pline("Blecch!  Rotten food!");
178                 if (!rn2(4)) {
179                         pline("You feel rather light headed.");
180                         Confusion += d(2, 4);
181                 } else if (!rn2(4) && !Blind) {
182                         pline("Everything suddenly goes dark.");
183                         Blind = d(2, 10);
184                         seeoff(0);
185                 } else if (!rn2(3)) {
186                         if (Blind)
187                                 pline("The world spins and you slap against the floor.");
188                         else
189                                 pline("The world spins and goes dark.");
190                         nomul(-rnd(10));
191                         nomovemsg = "You are conscious again.";
192                 }
193                 lesshungry(ftmp->nutrition / 4);
194         } else {
195                 if (u.uhunger >= 1500) {
196                         pline("You choke over your food.");
197                         pline("You die...");
198                         killer = ftmp->oc_name;
199                         done("choked");
200                 }
201                 switch (otmp->otyp) {
202                 case FOOD_RATION:
203                         if (u.uhunger <= 200)
204                                 pline("That food really hit the spot!");
205                         else if (u.uhunger <= 700)
206                                 pline("That satiated your stomach!");
207                         else {
208                                 pline("You're having a hard time getting all that food down.");
209                                 multi -= 2;
210                         }
211                         lesshungry(ftmp->nutrition);
212                         if (multi < 0)
213                                 nomovemsg = "You finished your meal.";
214                         break;
215                 case TRIPE_RATION:
216                         pline("Yak - dog food!");
217                         more_experienced(1, 0);
218                         flags.botl = 1;
219                         if (rn2(2)) {
220                                 pline("You vomit.");
221                                 morehungry(20);
222                                 if (Sick) {
223                                         Sick = 0;       /* David Neves */
224                                         pline("What a relief!");
225                                 }
226                         } else
227                                 lesshungry(ftmp->nutrition);
228                         break;
229                 default:
230                         if (otmp->otyp >= CORPSE)
231                                 pline("That %s tasted terrible!", ftmp->oc_name);
232                         else
233                                 pline("That %s was delicious!", ftmp->oc_name);
234                         lesshungry(ftmp->nutrition);
235                         if (otmp->otyp == DEAD_LIZARD && (Confusion > 2))
236                                 Confusion = 2;
237                         else
238 #ifdef QUEST
239                         if (otmp->otyp == CARROT && !Blind) {
240                                 u.uhorizon++;
241                                 setsee();
242                                 pline("Your vision improves.");
243                         } else
244 #endif /* QUEST */
245                         if (otmp->otyp == FORTUNE_COOKIE) {
246                                 if (Blind) {
247                                         pline("This cookie has a scrap of paper inside!");
248                                         pline("What a pity, that you cannot read it!");
249                                 } else
250                                         outrumor();
251                         } else if (otmp->otyp == LUMP_OF_ROYAL_JELLY) {
252                                 /* This stuff seems to be VERY healthy! */
253                                 if (u.ustrmax < 118)
254                                         u.ustrmax++;
255                                 if (u.ustr < u.ustrmax)
256                                         u.ustr++;
257                                 u.uhp += rnd(20);
258                                 if (u.uhp > u.uhpmax) {
259                                         if (!rn2(17))
260                                                 u.uhpmax++;
261                                         u.uhp = u.uhpmax;
262                                 }
263                                 heal_legs();
264                         }
265                         break;
266                 }
267         }
268 eatx:
269         if (multi < 0 && !nomovemsg) {
270                 static char msgbuf[BUFSZ];
271                 sprintf(msgbuf, "You finished eating the %s.", ftmp->oc_name);
272                 nomovemsg = msgbuf;
273         }
274         useup(otmp);
275         return (1);
276 }
277
278 /* called in hack.main.c */
279 void
280 gethungry(void)
281 {
282         --u.uhunger;
283         if (moves % 2) {
284                 if (Regeneration)
285                         u.uhunger--;
286                 if (Hunger)
287                         u.uhunger--;
288                 /* a3:  if (Hunger & LEFT_RING) u.uhunger--;
289                  *      if (Hunger & RIGHT_RING) u.uhunger--;
290                  * etc.
291                  */
292         }
293         if (moves % 20 == 0) {          /* jimt@asgb */
294                 if (uleft)
295                         u.uhunger--;
296                 if (uright)
297                         u.uhunger--;
298         }
299         newuhs(TRUE);
300 }
301
302 /* called after vomiting and after performing feats of magic */
303 void
304 morehungry(int num)
305 {
306         u.uhunger -= num;
307         newuhs(TRUE);
308 }
309
310 /* called after eating something (and after drinking fruit juice) */
311 void
312 lesshungry(int num)
313 {
314         u.uhunger += num;
315         newuhs(FALSE);
316 }
317
318 static void
319 unfaint(void)
320 {
321         u.uhs = FAINTING;
322         flags.botl = 1;
323 }
324
325 static void
326 newuhs(bool incr)
327 {
328         int newhs, h = u.uhunger;
329
330         newhs = (h > 1000) ? SATIATED :
331                 (h > 150) ? NOT_HUNGRY :
332                 (h > 50) ? HUNGRY :
333                 (h > 0) ? WEAK : FAINTING;
334
335         if (newhs == FAINTING) {
336                 if (u.uhs == FAINTED)
337                         newhs = FAINTED;
338                 if (u.uhs <= WEAK || rn2(20 - u.uhunger / 10) >= 19) {
339                         if (u.uhs != FAINTED && multi >= 0 /* %% */) {
340                                 pline("You faint from lack of food.");
341                                 nomul(-10 + (u.uhunger / 10));
342                                 nomovemsg = "You regain consciousness.";
343                                 afternmv = unfaint;
344                                 newhs = FAINTED;
345                         }
346                 } else if (u.uhunger < -(int)(200 + 25 * u.ulevel)) {
347                         u.uhs = STARVED;
348                         flags.botl = 1;
349                         bot();
350                         pline("You die from starvation.");
351                         done("starved");
352                 }
353         }
354
355         if (newhs != u.uhs) {
356                 if (newhs >= WEAK && u.uhs < WEAK)
357                         losestr(1);     /* this may kill you -- see below */
358                 else if (newhs < WEAK && u.uhs >= WEAK && u.ustr < u.ustrmax)
359                         losestr(-1);
360                 switch (newhs) {
361                 case HUNGRY:
362                         pline((!incr) ? "You only feel hungry now." :
363                               (u.uhunger < 145) ? "You feel hungry." :
364                               "You are beginning to feel hungry.");
365                         break;
366                 case WEAK:
367                         pline((!incr) ? "You feel weak now." :
368                               (u.uhunger < 45) ? "You feel weak." :
369                               "You are beginning to feel weak.");
370                         break;
371                 }
372                 u.uhs = newhs;
373                 flags.botl = 1;
374                 if (u.uhp < 1) {
375                         pline("You die from hunger and exhaustion.");
376                         killer = "exhaustion";
377                         done("starved");
378                 }
379         }
380 }
381
382 #define CORPSE_I_TO_C(otyp)     (char)((otyp >= DEAD_ACID_BLOB)\
383                                        ?  'a' + (otyp - DEAD_ACID_BLOB)\
384                                        :  '@' + (otyp - DEAD_HUMAN))
385 bool
386 poisonous(struct obj *otmp)
387 {
388         return (strchr(POISONOUS, CORPSE_I_TO_C(otmp->otyp)) != 0);
389 }
390
391 /* returns 1 if some text was printed */
392 static int
393 eatcorpse(struct obj *otmp)
394 {
395         char let = CORPSE_I_TO_C(otmp->otyp);
396         int tp = 0;
397
398         if (let != 'a' && moves > otmp->age + 50 + rn2(100)) {
399                 tp++;
400                 pline("Ulch -- that meat was tainted!");
401                 pline("You get very sick.");
402                 Sick = 10 + rn2(10);
403                 u.usick_cause = objects[otmp->otyp].oc_name;
404         } else if (strchr(POISONOUS, let) && rn2(5)) {
405                 tp++;
406                 pline("Ecch -- that must have been poisonous!");
407                 if (!Poison_resistance) {
408                         losestr(rnd(4));
409                         losehp(rnd(15), "poisonous corpse");
410                 } else
411                         pline("You don't seem affected by the poison.");
412         } else if (strchr("ELNOPQRUuxz", let) && rn2(5)) {
413                 tp++;
414                 pline("You feel sick.");
415                 losehp(rnd(8), "cadaver");
416         }
417         switch (let) {
418         case 'L':
419         case 'N':
420         case 't':
421                 Teleportation |= INTRINSIC;
422                 break;
423         case 'W':
424                 pluslvl();
425                 break;
426         case 'n':
427                 u.uhp = u.uhpmax;
428                 flags.botl = 1;
429         /* fall into next case */
430         case '@':
431                 pline("You cannibal! You will be sorry for this!");
432         /* not tp++; */
433         /* fall into next case */
434         case 'd':
435                 Aggravate_monster |= INTRINSIC;
436                 break;
437         case 'I':
438                 if (!Invis) {
439                         Invis = 50 + rn2(100);
440                         if (!See_invisible)
441                                 newsym(u.ux, u.uy);
442                 } else {
443                         Invis |= INTRINSIC;
444                         See_invisible |= INTRINSIC;
445                 }
446         /* fall into next case */
447         case 'y':
448 #ifdef QUEST
449                 u.uhorizon++;
450 #endif /* QUEST */
451         /* fall into next case */
452         case 'B':
453                 Confusion = 50;
454                 break;
455         case 'D':
456                 Fire_resistance |= INTRINSIC;
457                 break;
458         case 'E':
459                 Telepat |= INTRINSIC;
460                 break;
461         case 'F':
462         case 'Y':
463                 Cold_resistance |= INTRINSIC;
464                 break;
465         case 'k':
466         case 's':
467                 Poison_resistance |= INTRINSIC;
468                 break;
469         case 'c':
470                 pline("You turn to stone.");
471                 killer = "dead cockatrice";
472                 done("died");
473         /* NOTREACHED */
474         case 'a':
475                 if (Stoned) {
476                         pline("What a pity - you just destroyed a future piece of art!");
477                         tp++;
478                         Stoned = 0;
479                 }
480                 break;
481         case 'M':
482                 pline("You cannot resist the temptation to mimic a treasure chest.");
483                 tp++;
484                 nomul(-30);
485                 afternmv = Meatdone;
486                 nomovemsg = "You now again prefer mimicking a human.";
487                 u.usym = '$';
488                 prme();
489                 break;
490         }
491         return (tp);
492 }