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