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