xref: /netbsd/games/hack/hack.do.c (revision bf9ec67e)
1 /*	$NetBSD: hack.do.c,v 1.5 2001/03/25 20:43:59 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.do.c,v 1.5 2001/03/25 20:43:59 jsm Exp $");
10 #endif				/* not lint */
11 
12 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) and 't' (throw) */
13 
14 #include "hack.h"
15 #include "extern.h"
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 
20 
21 static int drop __P((struct obj *));
22 
23 int
24 dodrop()
25 {
26 	return (drop(getobj("0$#", "drop")));
27 }
28 
29 static int
30 drop(obj)
31 	struct obj     *obj;
32 {
33 	if (!obj)
34 		return (0);
35 	if (obj->olet == '$') {	/* pseudo object */
36 		long            amount = OGOLD(obj);
37 
38 		if (amount == 0)
39 			pline("You didn't drop any gold pieces.");
40 		else {
41 			mkgold(amount, u.ux, u.uy);
42 			pline("You dropped %ld gold piece%s.",
43 			      amount, plur(amount));
44 			if (Invisible)
45 				newsym(u.ux, u.uy);
46 		}
47 		free((char *) obj);
48 		return (1);
49 	}
50 	if (obj->owornmask & (W_ARMOR | W_RING)) {
51 		pline("You cannot drop something you are wearing.");
52 		return (0);
53 	}
54 	if (obj == uwep) {
55 		if (uwep->cursed) {
56 			pline("Your weapon is welded to your hand!");
57 			return (0);
58 		}
59 		setuwep((struct obj *) 0);
60 	}
61 	pline("You dropped %s.", doname(obj));
62 	dropx(obj);
63 	return (1);
64 }
65 
66 /* Called in several places - should not produce texts */
67 void
68 dropx(obj)
69 	struct obj     *obj;
70 {
71 	freeinv(obj);
72 	dropy(obj);
73 }
74 
75 void
76 dropy(obj)
77 	struct obj     *obj;
78 {
79 	if (obj->otyp == CRYSKNIFE)
80 		obj->otyp = WORM_TOOTH;
81 	obj->ox = u.ux;
82 	obj->oy = u.uy;
83 	obj->nobj = fobj;
84 	fobj = obj;
85 	if (Invisible)
86 		newsym(u.ux, u.uy);
87 	subfrombill(obj);
88 	stackobj(obj);
89 }
90 
91 /* drop several things */
92 int
93 doddrop()
94 {
95 	return (ggetobj("drop", drop, 0));
96 }
97 
98 int
99 dodown()
100 {
101 	if (u.ux != xdnstair || u.uy != ydnstair) {
102 		pline("You can't go down here.");
103 		return (0);
104 	}
105 	if (u.ustuck) {
106 		pline("You are being held, and cannot go down.");
107 		return (1);
108 	}
109 	if (Levitation) {
110 		pline("You're floating high above the stairs.");
111 		return (0);
112 	}
113 	goto_level(dlevel + 1, TRUE);
114 	return (1);
115 }
116 
117 int
118 doup()
119 {
120 	if (u.ux != xupstair || u.uy != yupstair) {
121 		pline("You can't go up here.");
122 		return (0);
123 	}
124 	if (u.ustuck) {
125 		pline("You are being held, and cannot go up.");
126 		return (1);
127 	}
128 	if (!Levitation && inv_weight() + 5 > 0) {
129 		pline("Your load is too heavy to climb the stairs.");
130 		return (1);
131 	}
132 	goto_level(dlevel - 1, TRUE);
133 	return (1);
134 }
135 
136 void
137 goto_level(newlevel, at_stairs)
138 	int             newlevel;
139 	boolean         at_stairs;
140 {
141 	int fd;
142 	boolean         up = (newlevel < dlevel);
143 
144 	if (newlevel <= 0)
145 		done("escaped");/* in fact < 0 is impossible */
146 	if (newlevel > MAXLEVEL)
147 		newlevel = MAXLEVEL;	/* strange ... */
148 	if (newlevel == dlevel)
149 		return;		/* this can happen */
150 
151 	glo(dlevel);
152 	fd = creat(lock, FMASK);
153 	if (fd < 0) {
154 		/*
155 		 * This is not quite impossible: e.g., we may have
156 		 * exceeded our quota. If that is the case then we
157 		 * cannot leave this level, and cannot save either.
158 		 * Another possibility is that the directory was not
159 		 * writable.
160 		 */
161 		pline("A mysterious force prevents you from going %s.",
162 		      up ? "up" : "down");
163 		return;
164 	}
165 	if (Punished)
166 		unplacebc();
167 	u.utrap = 0;		/* needed in level_tele */
168 	u.ustuck = 0;		/* idem */
169 	keepdogs();
170 	seeoff(1);
171 	if (u.uswallow)		/* idem */
172 		u.uswldtim = u.uswallow = 0;
173 	flags.nscrinh = 1;
174 	u.ux = FAR;		/* hack */
175 	(void) inshop();	/* probably was a trapdoor */
176 
177 	savelev(fd, dlevel);
178 	(void) close(fd);
179 
180 	dlevel = newlevel;
181 	if (maxdlevel < dlevel)
182 		maxdlevel = dlevel;
183 	glo(dlevel);
184 
185 	if (!level_exists[dlevel])
186 		mklev();
187 	else {
188 		if ((fd = open(lock, O_RDONLY)) < 0) {
189 			pline("Cannot open %s .", lock);
190 			pline("Probably someone removed it.");
191 			done("tricked");
192 		}
193 		getlev(fd, hackpid, dlevel);
194 		(void) close(fd);
195 	}
196 
197 	if (at_stairs) {
198 		if (up) {
199 			u.ux = xdnstair;
200 			u.uy = ydnstair;
201 			if (!u.ux) {	/* entering a maze from below? */
202 				u.ux = xupstair;	/* this will confuse the
203 							 * player! */
204 				u.uy = yupstair;
205 			}
206 			if (Punished && !Levitation) {
207 				pline("With great effort you climb the stairs.");
208 				placebc(1);
209 			}
210 		} else {
211 			u.ux = xupstair;
212 			u.uy = yupstair;
213 			if (inv_weight() + 5 > 0 || Punished) {
214 				pline("You fall down the stairs.");	/* %% */
215 				losehp(rnd(3), "fall");
216 				if (Punished) {
217 					if (uwep != uball && rn2(3)) {
218 						pline("... and are hit by the iron ball.");
219 						losehp(rnd(20), "iron ball");
220 					}
221 					placebc(1);
222 				}
223 				selftouch("Falling, you");
224 			}
225 		}
226 		{
227 			struct monst   *mtmp = m_at(u.ux, u.uy);
228 			if (mtmp)
229 				mnexto(mtmp);
230 		}
231 	} else {		/* trapdoor or level_tele */
232 		do {
233 			u.ux = rnd(COLNO - 1);
234 			u.uy = rn2(ROWNO);
235 		} while (levl[u.ux][u.uy].typ != ROOM ||
236 			 m_at(u.ux, u.uy));
237 		if (Punished) {
238 			if (uwep != uball && !up /* %% */ && rn2(5)) {
239 				pline("The iron ball falls on your head.");
240 				losehp(rnd(25), "iron ball");
241 			}
242 			placebc(1);
243 		}
244 		selftouch("Falling, you");
245 	}
246 	(void) inshop();
247 	initrack();
248 
249 	losedogs();
250 	{
251 		struct monst   *mtmp;
252 		if ((mtmp = m_at(u.ux, u.uy)) != NULL)
253 			mnexto(mtmp);	/* riv05!a3 */
254 	}
255 	flags.nscrinh = 0;
256 	setsee();
257 	seeobjs();		/* make old cadavers disappear - riv05!a3 */
258 	docrt();
259 	pickup(1);
260 	read_engr_at(u.ux, u.uy);
261 }
262 
263 int
264 donull()
265 {
266 	return (1);		/* Do nothing, but let other things happen */
267 }
268 
269 int
270 dopray()
271 {
272 	nomovemsg = "You finished your prayer.";
273 	nomul(-3);
274 	return (1);
275 }
276 
277 int
278 dothrow()
279 {
280 	struct obj     *obj;
281 	struct monst   *mon;
282 	int tmp;
283 
284 	obj = getobj("#)", "throw");	/* it is also possible to throw food */
285 	/* (or jewels, or iron balls ... ) */
286 	if (!obj || !getdir(1))	/* ask "in what direction?" */
287 		return (0);
288 	if (obj->owornmask & (W_ARMOR | W_RING)) {
289 		pline("You can't throw something you are wearing.");
290 		return (0);
291 	}
292 	u_wipe_engr(2);
293 
294 	if (obj == uwep) {
295 		if (obj->cursed) {
296 			pline("Your weapon is welded to your hand.");
297 			return (1);
298 		}
299 		if (obj->quan > 1)
300 			setuwep(splitobj(obj, 1));
301 		else
302 			setuwep((struct obj *) 0);
303 	} else if (obj->quan > 1)
304 		(void) splitobj(obj, 1);
305 	freeinv(obj);
306 	if (u.uswallow) {
307 		mon = u.ustuck;
308 		bhitpos.x = mon->mx;
309 		bhitpos.y = mon->my;
310 	} else if (u.dz) {
311 		if (u.dz < 0) {
312 			pline("%s hits the ceiling, then falls back on top of your head.",
313 			      Doname(obj));	/* note: obj->quan == 1 */
314 			if (obj->olet == POTION_SYM)
315 				potionhit(&youmonst, obj);
316 			else {
317 				if (uarmh)
318 					pline("Fortunately, you are wearing a helmet!");
319 				losehp(uarmh ? 1 : rnd((int) (obj->owt)), "falling object");
320 				dropy(obj);
321 			}
322 		} else {
323 			pline("%s hits the floor.", Doname(obj));
324 			if (obj->otyp == EXPENSIVE_CAMERA) {
325 				pline("It is shattered in a thousand pieces!");
326 				obfree(obj, Null(obj));
327 			} else if (obj->otyp == EGG) {
328 				pline("\"Splash!\"");
329 				obfree(obj, Null(obj));
330 			} else if (obj->olet == POTION_SYM) {
331 				pline("The flask breaks, and you smell a peculiar odor ...");
332 				potionbreathe(obj);
333 				obfree(obj, Null(obj));
334 			} else {
335 				dropy(obj);
336 			}
337 		}
338 		return (1);
339 	} else if (obj->otyp == BOOMERANG) {
340 		mon = boomhit(u.dx, u.dy);
341 		if (mon == &youmonst) {	/* the thing was caught */
342 			(void) addinv(obj);
343 			return (1);
344 		}
345 	} else {
346 		if (obj->otyp == PICK_AXE && shkcatch(obj))
347 			return (1);
348 
349 		mon = bhit(u.dx, u.dy, (obj->otyp == ICE_BOX) ? 1 :
350 			(!Punished || obj != uball) ? 8 : !u.ustuck ? 5 : 1,
351 			   obj->olet,
352 			   (void (*) __P((struct monst *, struct obj *))) 0,
353 			   (int (*) __P((struct obj *, struct obj *))) 0, obj);
354 	}
355 	if (mon) {
356 		/* awake monster if sleeping */
357 		wakeup(mon);
358 
359 		if (obj->olet == WEAPON_SYM) {
360 			tmp = -1 + u.ulevel + mon->data->ac + abon();
361 			if (obj->otyp < ROCK) {
362 				if (!uwep ||
363 				    uwep->otyp != obj->otyp + (BOW - ARROW))
364 					tmp -= 4;
365 				else {
366 					tmp += uwep->spe;
367 				}
368 			} else if (obj->otyp == BOOMERANG)
369 				tmp += 4;
370 			tmp += obj->spe;
371 			if (u.uswallow || tmp >= rnd(20)) {
372 				if (hmon(mon, obj, 1) == TRUE) {
373 					/* mon still alive */
374 #ifndef NOWORM
375 					cutworm(mon, bhitpos.x, bhitpos.y, obj->otyp);
376 #endif	/* NOWORM */
377 				} else
378 					mon = 0;
379 				/* weapons thrown disappear sometimes */
380 				if (obj->otyp < BOOMERANG && rn2(3)) {
381 					/* check bill; free */
382 					obfree(obj, (struct obj *) 0);
383 					return (1);
384 				}
385 			} else
386 				miss(objects[obj->otyp].oc_name, mon);
387 		} else if (obj->otyp == HEAVY_IRON_BALL) {
388 			tmp = -1 + u.ulevel + mon->data->ac + abon();
389 			if (!Punished || obj != uball)
390 				tmp += 2;
391 			if (u.utrap)
392 				tmp -= 2;
393 			if (u.uswallow || tmp >= rnd(20)) {
394 				if (hmon(mon, obj, 1) == FALSE)
395 					mon = 0;	/* he died */
396 			} else
397 				miss("iron ball", mon);
398 		} else if (obj->olet == POTION_SYM && u.ulevel > rn2(15)) {
399 			potionhit(mon, obj);
400 			return (1);
401 		} else {
402 			if (cansee(bhitpos.x, bhitpos.y))
403 				pline("You miss %s.", monnam(mon));
404 			else
405 				pline("You miss it.");
406 			if (obj->olet == FOOD_SYM && mon->data->mlet == 'd')
407 				if (tamedog(mon, obj))
408 					return (1);
409 			if (obj->olet == GEM_SYM && mon->data->mlet == 'u' &&
410 			    !mon->mtame) {
411 				if (obj->dknown && objects[obj->otyp].oc_name_known) {
412 					if (objects[obj->otyp].g_val > 0) {
413 						u.uluck += 5;
414 						goto valuable;
415 					} else {
416 						pline("%s is not interested in your junk.",
417 						      Monnam(mon));
418 					}
419 				} else {	/* value unknown to @ */
420 					u.uluck++;
421 			valuable:
422 					if (u.uluck > LUCKMAX)	/* dan@ut-ngp */
423 						u.uluck = LUCKMAX;
424 					pline("%s graciously accepts your gift.",
425 					      Monnam(mon));
426 					mpickobj(mon, obj);
427 					rloc(mon);
428 					return (1);
429 				}
430 			}
431 		}
432 	}
433 	/* the code following might become part of dropy() */
434 	if (obj->otyp == CRYSKNIFE)
435 		obj->otyp = WORM_TOOTH;
436 	obj->ox = bhitpos.x;
437 	obj->oy = bhitpos.y;
438 	obj->nobj = fobj;
439 	fobj = obj;
440 	/* prevent him from throwing articles to the exit and escaping */
441 	/* subfrombill(obj); */
442 	stackobj(obj);
443 	if (Punished && obj == uball &&
444 	    (bhitpos.x != u.ux || bhitpos.y != u.uy)) {
445 		freeobj(uchain);
446 		unpobj(uchain);
447 		if (u.utrap) {
448 			if (u.utraptype == TT_PIT)
449 				pline("The ball pulls you out of the pit!");
450 			else {
451 				long            side =
452 				rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
453 				pline("The ball pulls you out of the bear trap.");
454 				pline("Your %s leg is severely damaged.",
455 				    (side == LEFT_SIDE) ? "left" : "right");
456 				set_wounded_legs(side, 500 + rn2(1000));
457 				losehp(2, "thrown ball");
458 			}
459 			u.utrap = 0;
460 		}
461 		unsee();
462 		uchain->nobj = fobj;
463 		fobj = uchain;
464 		u.ux = uchain->ox = bhitpos.x - u.dx;
465 		u.uy = uchain->oy = bhitpos.y - u.dy;
466 		setsee();
467 		(void) inshop();
468 	}
469 	if (cansee(bhitpos.x, bhitpos.y))
470 		prl(bhitpos.x, bhitpos.y);
471 	return (1);
472 }
473 
474 /* split obj so that it gets size num */
475 /* remainder is put in the object structure delivered by this call */
476 struct obj     *
477 splitobj(obj, num)
478 	struct obj     *obj;
479 	int             num;
480 {
481 	struct obj     *otmp;
482 	otmp = newobj(0);
483 	*otmp = *obj;		/* copies whole structure */
484 	otmp->o_id = flags.ident++;
485 	otmp->onamelth = 0;
486 	obj->quan = num;
487 	obj->owt = weight(obj);
488 	otmp->quan -= num;
489 	otmp->owt = weight(otmp);	/* -= obj->owt ? */
490 	obj->nobj = otmp;
491 	if (obj->unpaid)
492 		splitbill(obj, otmp);
493 	return (otmp);
494 }
495 
496 void
497 more_experienced(exp, rexp)
498 	int             exp, rexp;
499 {
500 	u.uexp += exp;
501 	u.urexp += 4 * exp + rexp;
502 	if (exp)
503 		flags.botl = 1;
504 	if (u.urexp >= ((pl_character[0] == 'W') ? 1000 : 2000))
505 		flags.beginner = 0;
506 }
507 
508 void
509 set_wounded_legs(side, timex)
510 	long            side;
511 	int             timex;
512 {
513 	if (!Wounded_legs || (Wounded_legs & TIMEOUT))
514 		Wounded_legs |= side + timex;
515 	else
516 		Wounded_legs |= side;
517 }
518 
519 void
520 heal_legs()
521 {
522 	if (Wounded_legs) {
523 		if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
524 			pline("Your legs feel somewhat better.");
525 		else
526 			pline("Your leg feels somewhat better.");
527 		Wounded_legs = 0;
528 	}
529 }
530