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