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