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