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