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