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