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