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