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