1 /* SCCS Id: @(#)do.c 3.4 2003/12/02 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
4
5 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
6
7 #include "hack.h"
8 #include "lev.h"
9
10 #ifdef SINKS
11 # ifdef OVLB
12 STATIC_DCL void FDECL(trycall, (struct obj *));
13 # endif /* OVLB */
14 STATIC_DCL void FDECL(dosinkring, (struct obj *));
15 #endif /* SINKS */
16
17 STATIC_PTR int FDECL(drop, (struct obj *));
18 STATIC_PTR int NDECL(wipeoff);
19
20 #ifdef OVL0
21 STATIC_DCL int FDECL(menu_drop, (int));
22 #endif
23 #ifdef OVL2
24 STATIC_DCL int NDECL(currentlevel_rewrite);
25 STATIC_DCL void NDECL(final_level);
26 /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
27 #endif
28
29 #ifdef OVLB
30
31 static NEARDATA const char drop_types[] =
32 { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
33
34 /* 'd' command: drop one inventory item */
35 int
dodrop()36 dodrop()
37 {
38 #ifndef GOLDOBJ
39 int result, i = (invent || u.ugold) ? 0 : (SIZE(drop_types) - 1);
40 #else
41 int result, i = (invent) ? 0 : (SIZE(drop_types) - 1);
42 #endif
43
44 if (*u.ushops) sellobj_state(SELL_DELIBERATE);
45 result = drop(getobj(&drop_types[i], "drop"));
46 if (*u.ushops) sellobj_state(SELL_NORMAL);
47 reset_occupations();
48
49 return result;
50 }
51
52 #endif /* OVLB */
53 #ifdef OVL0
54
55 /* Called when a boulder is dropped, thrown, or pushed. If it ends up
56 * in a pool, it either fills the pool up or sinks away. In either case,
57 * it's gone for good... If the destination is not a pool, returns FALSE.
58 */
59 boolean
boulder_hits_pool(otmp,rx,ry,pushing)60 boulder_hits_pool(otmp, rx, ry, pushing)
61 struct obj *otmp;
62 register int rx, ry;
63 boolean pushing;
64 {
65 if (!otmp || otmp->otyp != BOULDER)
66 warning("Not a boulder?");
67 else if (!Is_waterlevel(&u.uz) && (is_pool(rx,ry) || is_lava(rx,ry))) {
68 boolean lava = is_lava(rx,ry), fills_up;
69 const char *what = waterbody_name(rx,ry);
70 schar ltyp = levl[rx][ry].typ;
71 int chance = rn2(10); /* water: 90%; lava: 10% */
72 fills_up = lava ? chance == 0 : chance != 0;
73
74 if (fills_up) {
75 struct trap *ttmp = t_at(rx, ry);
76
77 if (ltyp == DRAWBRIDGE_UP) {
78 levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
79 levl[rx][ry].drawbridgemask |= DB_FLOOR;
80 } else
81 levl[rx][ry].typ = ROOM;
82
83 if (ttmp) (void) delfloortrap(ttmp);
84 bury_objs(rx, ry);
85
86 newsym(rx,ry);
87 if (pushing) {
88 You("push %s into the %s.", the(xname(otmp)), what);
89 if (flags.verbose && !Blind)
90 pline("Now you can cross it!");
91 /* no splashing in this case */
92 }
93 }
94 if (!fills_up || !pushing) { /* splashing occurs */
95 if (!u.uinwater) {
96 if (pushing ? !Blind : cansee(rx,ry)) {
97 There("is a large splash as %s %s the %s.",
98 the(xname(otmp)), fills_up? "fills":"falls into",
99 what);
100 } else if (flags.soundok)
101 You_hear("a%s splash.", lava ? " sizzling" : "");
102 wake_nearto(rx, ry, 40);
103 }
104
105 if (fills_up && u.uinwater && distu(rx,ry) == 0) {
106 u.uinwater = 0;
107 docrt();
108 vision_full_recalc = 1;
109 You("find yourself on dry land again!");
110 } else if (lava && distu(rx,ry) <= 2) {
111 You("are hit by molten lava%c",
112 Fire_resistance ? '.' : '!');
113 burn_away_slime();
114 losehp(d((Fire_resistance ? 1 : 3), 6),
115 "molten lava", KILLED_BY);
116 } else if (!fills_up && flags.verbose &&
117 (pushing ? !Blind : cansee(rx,ry)))
118 pline("It sinks without a trace!");
119 }
120
121 /* boulder is now gone */
122 if (pushing) delobj(otmp);
123 else obfree(otmp, (struct obj *)0);
124 return TRUE;
125 }
126 return FALSE;
127 }
128
129 /* Used for objects which sometimes do special things when dropped; must be
130 * called with the object not in any chain. Returns TRUE if the object goes
131 * away.
132 */
133 boolean
flooreffects(obj,x,y,verb)134 flooreffects(obj,x,y,verb)
135 struct obj *obj;
136 int x,y;
137 const char *verb;
138 {
139 struct trap *t;
140 struct monst *mtmp;
141
142 if (obj->where != OBJ_FREE)
143 panic("flooreffects: obj not free (%d)", obj->where);
144
145 /* make sure things like water_damage() have no pointers to follow */
146 obj->nobj = obj->nexthere = (struct obj *)0;
147
148 if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE))
149 return TRUE;
150 else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 &&
151 (t->ttyp==PIT || t->ttyp==SPIKED_PIT
152 || t->ttyp==TRAPDOOR || t->ttyp==HOLE)) {
153 if (((mtmp = m_at(x, y)) && mtmp->mtrapped) ||
154 (u.utrap && u.ux == x && u.uy == y)) {
155 if (*verb)
156 pline_The("boulder %s into the pit%s.",
157 vtense((const char *)0, verb),
158 (mtmp) ? "" : " with you");
159 if (mtmp) {
160 if (!passes_walls(mtmp->data) &&
161 !throws_rocks(mtmp->data)) {
162 if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data))
163 return FALSE; /* still alive */
164 }
165 mtmp->mtrapped = 0;
166 } else {
167 if (!Passes_walls && !throws_rocks(youmonst.data)) {
168 losehp(rnd(15), "squished under a boulder",
169 NO_KILLER_PREFIX);
170 return FALSE; /* player remains trapped */
171 } else u.utrap = 0;
172 }
173 }
174 if (*verb) {
175 if (Blind) {
176 if ((x == u.ux) && (y == u.uy))
177 You_hear("a CRASH! beneath you.");
178 else
179 You_hear("the boulder %s.", verb);
180 } else if (cansee(x, y)) {
181 pline_The("boulder %s%s.",
182 t->tseen ? "" : "triggers and ",
183 t->ttyp == TRAPDOOR ? "plugs a trap door" :
184 t->ttyp == HOLE ? "plugs a hole" :
185 "fills a pit");
186 }
187 }
188 deltrap(t);
189 obfree(obj, (struct obj *)0);
190 bury_objs(x, y);
191 newsym(x,y);
192 return TRUE;
193 } else if (obj->otyp==AMULET_OF_YENDOR &&
194 (obj->cursed ? rnf(1,2) :
195 obj->blessed ? rnf(1,16) : rnf(1,4))) {
196 /* prevent recursive call of teleportation through flooreffects */
197 if (!obj->orecursive &&
198 distu(x,y) < 9) {
199 if (Blind) {
200 You_hear("%s!",
201 (Hallucination) ? "nothing special happening" :
202 "something teleporting");
203 } else if (cansee(x,y)) {
204 pline("Right after touching the %s the %s teleports away!",
205 surface(x, y),
206 (Hallucination) ? "teddy bear" : "amulet");
207 }
208 obj->orecursive = TRUE;
209 rloco(obj);
210 obj->orecursive = FALSE;
211 return TRUE;
212 } else {
213 return FALSE;
214 }
215 } else if (is_lava(x, y)) {
216 return fire_damage(obj, FALSE, FALSE, x, y);
217 } else if (is_pool(x, y)) {
218 /* Reasonably bulky objects (arbitrary) splash when dropped.
219 * If you're floating above the water even small things make noise.
220 * Stuff dropped near fountains always misses */
221 if ((Blind || (Levitation || Flying)) && flags.soundok &&
222 ((x == u.ux) && (y == u.uy))) {
223 if (!Underwater) {
224 if (weight(obj) > 9) {
225 pline("Splash!");
226 } else if (Levitation || Flying) {
227 pline("Plop!");
228 }
229 }
230 map_background(x, y, 0);
231 newsym(x, y);
232 }
233 return water_damage(obj, FALSE, FALSE);
234 } else if (u.ux == x && u.uy == y &&
235 (!u.utrap || u.utraptype != TT_PIT) &&
236 (t = t_at(x,y)) != 0 && t->tseen &&
237 (t->ttyp==PIT || t->ttyp==SPIKED_PIT)) {
238 /* you escaped a pit and are standing on the precipice */
239 if (Blind && flags.soundok)
240 You_hear("%s %s downwards.",
241 The(xname(obj)), otense(obj, "tumble"));
242 else
243 pline("%s %s into %s pit.",
244 The(xname(obj)), otense(obj, "tumble"),
245 the_your[t->madeby_u]);
246 }
247 return FALSE;
248 }
249
250 #endif /* OVL0 */
251 #ifdef OVLB
252
253 void
doaltarobj(obj)254 doaltarobj(obj) /* obj is an object dropped on an altar */
255 register struct obj *obj;
256 {
257 if (Blind)
258 return;
259
260 /* KMH, conduct */
261 u.uconduct.gnostic++;
262
263 if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) {
264 There("is %s flash as %s %s the altar.",
265 an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)),
266 doname(obj), otense(obj, "hit"));
267 if (!Hallucination) obj->bknown = 1;
268 } else {
269 pline("%s %s on the altar.", Doname2(obj),
270 otense(obj, "land"));
271 obj->bknown = 1;
272 }
273 }
274
275 #ifdef SINKS
276 STATIC_OVL
277 void
trycall(obj)278 trycall(obj)
279 register struct obj *obj;
280 {
281 if(!objects[obj->otyp].oc_name_known &&
282 !objects[obj->otyp].oc_uname)
283 docall(obj);
284 }
285
286 /** Transforms the sink at the player's position into
287 * a fountain, throne, altar or grave. */
288 STATIC_OVL
289 void
polymorph_sink()290 polymorph_sink()
291 {
292 if (levl[u.ux][u.uy].typ != SINK) { return; }
293
294 level.flags.nsinks--;
295 levl[u.ux][u.uy].doormask = 0;
296 switch(rn2(4)) {
297 case 0:
298 levl[u.ux][u.uy].typ = FOUNTAIN;
299 level.flags.nfountains++;
300 break;
301 case 1:
302 levl[u.ux][u.uy].typ = THRONE;
303 break;
304 case 2:
305 levl[u.ux][u.uy].typ = ALTAR;
306 levl[u.ux][u.uy].altarmask = Align2amask(rn2((int)A_LAWFUL+2) - 1);
307 break;
308 case 3:
309 levl[u.ux][u.uy].typ = ROOM;
310 make_grave(u.ux, u.uy, (char *) 0);
311 break;
312 }
313 pline_The("sink transforms into %s!",
314 (levl[u.ux][u.uy].typ == THRONE) ?
315 "a throne" : an(surface(u.ux, u.uy)));
316 newsym(u.ux,u.uy);
317 }
318
319 /** Teleports the sink at the player's position.
320 * @return TRUE if sink teleported */
321 STATIC_OVL
322 boolean
teleport_sink()323 teleport_sink()
324 {
325 int cx, cy;
326 int cnt = 0;
327 struct trap *trp;
328 do {
329 cx = rnd(COLNO-1);
330 cy = rn2(ROWNO);
331 trp = t_at(cx,cy);
332 } while (((levl[cx][cy].typ != ROOM) ||
333 (trp) ||
334 cansee(cx,cy)) &&
335 (cnt++ < 200));
336 if ((levl[cx][cy].typ == ROOM) && !trp) {
337 /* create sink at new position */
338 levl[cx][cy].typ = SINK;
339 levl[cx][cy].looted = levl[u.ux][u.uy].looted;
340 newsym(cx,cy);
341 /* remove old sink */
342 levl[u.ux][u.uy].typ = ROOM;
343 levl[u.ux][u.uy].looted = 0;
344 newsym(u.ux,u.uy);
345 return TRUE;
346 }
347 return FALSE;
348 }
349
350 STATIC_OVL
351 void
dosinkring(obj)352 dosinkring(obj) /* obj is a ring being dropped over a kitchen sink */
353 register struct obj *obj;
354 {
355 register struct obj *otmp,*otmp2;
356 register boolean ideed = TRUE;
357
358 You("drop %s down the drain.", doname(obj));
359 obj->in_use = TRUE; /* block free identification via interrupt */
360 switch(obj->otyp) { /* effects that can be noticed without eyes */
361 case RIN_SEARCHING:
362 You("thought your %s got lost in the sink, but there it is!",
363 xname(obj));
364 goto giveback;
365 case RIN_SLOW_DIGESTION:
366 pline_The("ring is regurgitated!");
367 giveback:
368 obj->in_use = FALSE;
369 dropx(obj);
370 trycall(obj);
371 return;
372 case RIN_LEVITATION:
373 pline_The("sink quivers upward for a moment.");
374 break;
375 case RIN_POISON_RESISTANCE:
376 You("smell rotten %s.", makeplural(fruitname(FALSE)));
377 break;
378 case RIN_AGGRAVATE_MONSTER:
379 pline("Several %s buzz angrily around the sink.",
380 Hallucination ? makeplural(rndmonnam()) : "flies");
381 break;
382 case RIN_SHOCK_RESISTANCE:
383 pline("Static electricity surrounds the sink.");
384 break;
385 case RIN_CONFLICT:
386 You_hear("loud noises coming from the drain.");
387 break;
388 case RIN_SUSTAIN_ABILITY: /* KMH */
389 pline_The("water flow seems fixed.");
390 break;
391 case RIN_GAIN_STRENGTH:
392 pline_The("water flow seems %ser now.",
393 (obj->spe<0) ? "weak" : "strong");
394 break;
395 case RIN_GAIN_CONSTITUTION:
396 pline_The("water flow seems %ser now.",
397 (obj->spe<0) ? "less" : "great");
398 break;
399 case RIN_GAIN_INTELLIGENCE:
400 pline("The water seems %ser now.",
401 (obj->spe<0) ? "dimm" : "bright");
402 break;
403 case RIN_GAIN_WISDOM:
404 pline("The water flow seems %ser now.",
405 (obj->spe<0) ? "dull" : "quick");
406 break;
407 case RIN_GAIN_DEXTERITY:
408 pline("The water flow seems %ser now.",
409 (obj->spe<0) ? "slow" : "fast");
410 break;
411 case RIN_INCREASE_ACCURACY: /* KMH */
412 pline_The("water flow %s the drain.",
413 (obj->spe<0) ? "misses" : "hits");
414 break;
415 case RIN_INCREASE_DAMAGE:
416 pline_The("water's force seems %ser now.",
417 (obj->spe<0) ? "small" : "great");
418 break;
419 case RIN_HUNGER:
420 ideed = FALSE;
421 for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
422 otmp2 = otmp->nexthere;
423 if (otmp != uball && otmp != uchain &&
424 !obj_resists(otmp, 1, 99)) {
425 if (!Blind) {
426 pline("Suddenly, %s %s from the sink!",
427 doname(otmp), otense(otmp, "vanish"));
428 ideed = TRUE;
429 }
430 delobj(otmp);
431 }
432 }
433 break;
434 case MEAT_RING:
435 /* Not the same as aggravate monster; besides, it's obvious. */
436 pline("Several %s buzz around the sink.",
437 Hallucination ? makeplural(rndmonnam()) : "flies");
438 break;
439 default:
440 ideed = FALSE;
441 break;
442 }
443 if(!Blind && !ideed && obj->otyp != RIN_HUNGER) {
444 ideed = TRUE;
445 switch(obj->otyp) { /* effects that need eyes */
446 case RIN_ADORNMENT:
447 pline_The("faucets flash brightly for a moment.");
448 break;
449 case RIN_REGENERATION:
450 pline_The("sink looks as good as new.");
451 break;
452 case RIN_INVISIBILITY:
453 pline_The("water flow momentarily vanishes.");
454 break;
455 case RIN_FREE_ACTION:
456 You("see the ring slide right down the drain!");
457 break;
458 case RIN_SEE_INVISIBLE:
459 You("see some %s in the sink.",
460 Hallucination ? "oxygen molecules" : "air");
461 break;
462 case RIN_STEALTH:
463 pline_The("sink seems to blend into the floor for a moment.");
464 break;
465 case RIN_FIRE_RESISTANCE:
466 pline_The("hot water faucet flashes brightly for a moment.");
467 break;
468 case RIN_COLD_RESISTANCE:
469 pline_The("cold water faucet flashes brightly for a moment.");
470 break;
471 case RIN_PROTECTION_FROM_SHAPE_CHAN:
472 pline_The("sink looks nothing like a fountain.");
473 break;
474 case RIN_PROTECTION:
475 pline_The("sink glows %s for a moment.",
476 hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER));
477 break;
478 case RIN_WARNING:
479 pline_The("sink glows %s for a moment.", hcolor(NH_RED));
480 break;
481 case RIN_TELEPORTATION:
482 if (teleport_sink())
483 pline_The("sink vanishes.");
484 else
485 pline_The("sink momentarily vanishes.");
486 break;
487 case RIN_TELEPORT_CONTROL:
488 pline_The("sink looks like it is being beamed aboard somewhere.");
489 break;
490 case RIN_POLYMORPH:
491 polymorph_sink();
492 break;
493 case RIN_POLYMORPH_CONTROL:
494 pline_The("sink transforms into another sink!");
495 levl[u.ux][u.uy].looted = 0;
496 break;
497 }
498 }
499 if(ideed)
500 trycall(obj);
501 else
502 You_hear("the ring bouncing down the drainpipe.");
503 if (!rn2(20)) {
504 pline_The("sink backs up, leaving %s.", doname(obj));
505 obj->in_use = FALSE;
506 dropx(obj);
507 } else
508 useup(obj);
509 }
510 #endif
511
512 #endif /* OVLB */
513 #ifdef OVL0
514
515 /* some common tests when trying to drop or throw items */
516 boolean
canletgo(obj,word)517 canletgo(obj,word)
518 register struct obj *obj;
519 register const char *word;
520 {
521 if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){
522 if (*word)
523 Norep("You cannot %s %s you are wearing.",word,
524 something);
525 return(FALSE);
526 }
527 if (obj->otyp == LOADSTONE && obj->cursed) {
528 /* getobj() kludge sets corpsenm to user's specified count
529 when refusing to split a stack of cursed loadstones */
530 if (*word) {
531 /* getobj() ignores a count for throwing since that is
532 implicitly forced to be 1; replicate its kludge... */
533 if (!strcmp(word, "throw") && obj->quan > 1L)
534 obj->corpsenm = 1;
535 pline("For some reason, you cannot %s%s the stone%s!",
536 word, obj->corpsenm ? " any of" : "",
537 plur(obj->quan));
538 }
539 obj->corpsenm = 0; /* reset */
540 obj->bknown = 1;
541 return(FALSE);
542 }
543 if (obj->otyp == LEASH && obj->leashmon != 0) {
544 if (*word)
545 pline_The("leash is tied around your %s.",
546 body_part(HAND));
547 return(FALSE);
548 }
549 #ifdef STEED
550 if (obj->owornmask & W_SADDLE) {
551 if (*word)
552 You("cannot %s %s you are sitting on.", word,
553 something);
554 return (FALSE);
555 }
556 #endif
557 return(TRUE);
558 }
559
560 STATIC_PTR
561 int
drop(obj)562 drop(obj)
563 register struct obj *obj;
564 {
565 if(!obj) return(0);
566 if(!canletgo(obj,"drop"))
567 return(0);
568 if(obj == uwep) {
569 if(welded(uwep)) {
570 weldmsg(obj);
571 return(0);
572 }
573 setuwep((struct obj *)0);
574 }
575 if(obj == uquiver) {
576 setuqwep((struct obj *)0);
577 }
578 if (obj == uswapwep) {
579 setuswapwep((struct obj *)0);
580 }
581
582 obj->was_dropped = TRUE;
583
584 if (u.uswallow) {
585 /* barrier between you and the floor */
586 if(flags.verbose)
587 {
588 char buf[BUFSZ];
589
590 /* doname can call s_suffix, reusing its buffer */
591 Strcpy(buf, s_suffix(mon_nam(u.ustuck)));
592 You("drop %s into %s %s.", doname(obj), buf,
593 mbodypart(u.ustuck, STOMACH));
594 }
595 } else {
596 #ifdef SINKS
597 if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) &&
598 IS_SINK(levl[u.ux][u.uy].typ)) {
599 dosinkring(obj);
600 return(1);
601 }
602 #endif
603 if (!can_reach_floor()) {
604 if(flags.verbose) You("drop %s.", doname(obj));
605 #ifndef GOLDOBJ
606 if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
607 #else
608 /* Ensure update when we drop gold objects */
609 if (obj->oclass == COIN_CLASS) flags.botl = 1;
610 freeinv(obj);
611 #endif
612 hitfloor(obj);
613 return(1);
614 }
615 if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
616 You("drop %s.", doname(obj));
617 }
618 dropx(obj);
619 return(1);
620 }
621
622 /* Called in several places - may produce output */
623 /* eg ship_object() and dropy() -> sellobj() both produce output */
624 void
dropx(obj)625 dropx(obj)
626 register struct obj *obj;
627 {
628 #ifndef GOLDOBJ
629 if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj);
630 #else
631 /* Ensure update when we drop gold objects */
632 if (obj->oclass == COIN_CLASS) flags.botl = 1;
633 freeinv(obj);
634 #endif
635 if (!u.uswallow) {
636 if (ship_object(obj, u.ux, u.uy, FALSE)) return;
637 if (IS_ALTAR(levl[u.ux][u.uy].typ))
638 doaltarobj(obj); /* set bknown */
639 }
640 dropy(obj);
641 }
642
643 void
dropy(obj)644 dropy(obj)
645 register struct obj *obj;
646 {
647 if (obj == uwep) setuwep((struct obj *)0);
648 if (obj == uquiver) setuqwep((struct obj *)0);
649 if (obj == uswapwep) setuswapwep((struct obj *)0);
650
651 if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
652 /* uswallow check done by GAN 01/29/87 */
653 if(u.uswallow) {
654 boolean could_petrify = FALSE;
655 boolean could_poly = FALSE;
656 boolean could_slime = FALSE;
657 boolean could_grow = FALSE;
658 boolean could_heal = FALSE;
659
660 if (obj != uball) { /* mon doesn't pick up ball */
661 if (obj->otyp == CORPSE) {
662 could_petrify = touch_petrifies(&mons[obj->corpsenm]);
663 could_poly = polyfodder(obj);
664 could_slime = (obj->corpsenm == PM_GREEN_SLIME);
665 could_grow = (obj->corpsenm == PM_WRAITH);
666 could_heal = (obj->corpsenm == PM_NURSE);
667 }
668 (void) mpickobj(u.ustuck,obj);
669 if (is_animal(u.ustuck->data)) {
670 if (could_poly || could_slime) {
671 (void) newcham(u.ustuck,
672 could_poly ? (struct permonst *)0 :
673 &mons[PM_GREEN_SLIME],
674 FALSE, could_slime);
675 delobj(obj); /* corpse is digested */
676 } else if (could_petrify) {
677 minstapetrify(u.ustuck, TRUE);
678 /* Don't leave a cockatrice corpse in a statue */
679 if (!u.uswallow) delobj(obj);
680 } else if (could_grow) {
681 (void) grow_up(u.ustuck, (struct monst *)0);
682 delobj(obj); /* corpse is digested */
683 } else if (could_heal) {
684 u.ustuck->mhp = u.ustuck->mhpmax;
685 delobj(obj); /* corpse is digested */
686 }
687 }
688 }
689 } else {
690 place_object(obj, u.ux, u.uy);
691 if (obj == uball)
692 drop_ball(u.ux,u.uy);
693 else
694 sellobj(obj, u.ux, u.uy);
695 stackobj(obj);
696 if(Blind && Levitation)
697 map_object(obj, 0);
698 newsym(u.ux,u.uy); /* remap location under self */
699 }
700 }
701
702 /* things that must change when not held; recurse into containers.
703 Called for both player and monsters */
704 void
obj_no_longer_held(obj)705 obj_no_longer_held(obj)
706 struct obj *obj;
707 {
708 if (!obj) {
709 return;
710 } else if ((Is_container(obj) || obj->otyp == STATUE) && obj->cobj) {
711 struct obj *contents;
712 for(contents=obj->cobj; contents; contents=contents->nobj)
713 obj_no_longer_held(contents);
714 }
715 switch(obj->otyp) {
716 case CRYSKNIFE:
717 /* KMH -- Fixed crysknives have only 10% chance of reverting */
718 /* only changes when not held by player or monster */
719 if (!obj->oerodeproof || !rn2(10)) {
720 obj->otyp = WORM_TOOTH;
721 obj->oerodeproof = 0;
722 }
723 break;
724 }
725 }
726
727 /* 'D' command: drop several things */
728 int
doddrop()729 doddrop()
730 {
731 int result = 0;
732
733 add_valid_menu_class(0); /* clear any classes already there */
734 if (*u.ushops) sellobj_state(SELL_DELIBERATE);
735 if (flags.menu_style != MENU_TRADITIONAL ||
736 (result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1)
737 result = menu_drop(result);
738 if (*u.ushops) sellobj_state(SELL_NORMAL);
739 reset_occupations();
740
741 return result;
742 }
743
744 /* Drop things from the hero's inventory, using a menu. */
745 STATIC_OVL int
menu_drop(retry)746 menu_drop(retry)
747 int retry;
748 {
749 int n, i, n_dropped = 0;
750 long cnt;
751 struct obj *otmp, *otmp2;
752 #ifndef GOLDOBJ
753 struct obj *u_gold = 0;
754 #endif
755 menu_item *pick_list;
756 boolean all_categories = TRUE;
757 boolean drop_everything = FALSE;
758
759 #ifndef GOLDOBJ
760 if (u.ugold) {
761 /* Hack: gold is not in the inventory, so make a gold object
762 and put it at the head of the inventory list. */
763 u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */
764 u_gold->in_use = TRUE;
765 u.ugold = u_gold->quan; /* put the gold back */
766 assigninvlet(u_gold); /* might end up as NOINVSYM */
767 u_gold->nobj = invent;
768 invent = u_gold;
769 }
770 #endif
771 if (retry) {
772 all_categories = (retry == -2);
773 } else if (flags.menu_style == MENU_FULL) {
774 all_categories = FALSE;
775 n = query_category("Drop what type of items?",
776 invent,
777 UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL |
778 BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN,
779 &pick_list, PICK_ANY);
780 if (!n) goto drop_done;
781 for (i = 0; i < n; i++) {
782 if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
783 all_categories = TRUE;
784 else if (pick_list[i].item.a_int == 'A')
785 drop_everything = TRUE;
786 else
787 add_valid_menu_class(pick_list[i].item.a_int);
788 }
789 free((genericptr_t) pick_list);
790 } else if (flags.menu_style == MENU_COMBINATION) {
791 unsigned ggoresults = 0;
792 all_categories = FALSE;
793 /* Gather valid classes via traditional NetHack method */
794 i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
795 if (i == -2) all_categories = TRUE;
796 if (ggoresults & ALL_FINISHED) {
797 n_dropped = i;
798 goto drop_done;
799 }
800 }
801
802 if (drop_everything) {
803 for(otmp = invent; otmp; otmp = otmp2) {
804 otmp2 = otmp->nobj;
805 n_dropped += drop(otmp);
806 }
807 } else {
808 /* should coordinate with perm invent, maybe not show worn items */
809 n = query_objlist("What would you like to drop?", invent,
810 USE_INVLET|INVORDER_SORT, &pick_list,
811 PICK_ANY, all_categories ? allow_all : allow_category);
812 if (n > 0) {
813 for (i = 0; i < n; i++) {
814 otmp = pick_list[i].item.a_obj;
815 cnt = pick_list[i].count;
816 if (cnt < otmp->quan) {
817 if (welded(otmp)) {
818 ; /* don't split */
819 } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
820 /* same kludge as getobj(), for canletgo()'s use */
821 otmp->corpsenm = (int) cnt; /* don't split */
822 } else {
823 #ifndef GOLDOBJ
824 if (otmp->oclass == COIN_CLASS)
825 (void) splitobj(otmp, otmp->quan - cnt);
826 else
827 #endif
828 otmp = splitobj(otmp, cnt);
829 }
830 }
831 n_dropped += drop(otmp);
832 }
833 free((genericptr_t) pick_list);
834 }
835 }
836
837 drop_done:
838 #ifndef GOLDOBJ
839 if (u_gold && invent && invent->oclass == COIN_CLASS) {
840 /* didn't drop [all of] it */
841 u_gold = invent;
842 invent = u_gold->nobj;
843 u_gold->in_use = FALSE;
844 dealloc_obj(u_gold);
845 update_inventory();
846 }
847 #endif
848 return n_dropped;
849 }
850
851 #endif /* OVL0 */
852 #ifdef OVL2
853
854 /* on a ladder, used in goto_level */
855 static NEARDATA boolean at_ladder = FALSE;
856
857 int
dodown()858 dodown()
859 {
860 struct trap *trap = 0;
861 boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) ||
862 (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)),
863 ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
864
865 #ifdef STEED
866 if (u.usteed && !u.usteed->mcanmove) {
867 pline("%s won't move!", Monnam(u.usteed));
868 return(0);
869 } else if (u.usteed && u.usteed->meating) {
870 pline("%s is still eating.", Monnam(u.usteed));
871 return(0);
872 } else
873 #endif
874 if (Levitation) {
875 if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
876 /* end controlled levitation */
877 if (ELevitation & W_ARTI) {
878 struct obj *obj;
879
880 for(obj = invent; obj; obj = obj->nobj) {
881 if (obj->oartifact &&
882 artifact_has_invprop(obj,LEVITATION)) {
883 if (obj->age < monstermoves)
884 obj->age = monstermoves + rnz(100);
885 else
886 obj->age += rnz(100);
887 }
888 }
889 }
890 if (float_down(I_SPECIAL|TIMEOUT, W_ARTI))
891 return (1); /* came down, so moved */
892 }
893 floating_above(stairs_down ? "stairs" : ladder_down ?
894 "ladder" : surface(u.ux, u.uy));
895 return (0); /* didn't move */
896 }
897 if (!stairs_down && !ladder_down) {
898 if (!(trap = t_at(u.ux,u.uy)) ||
899 (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE &&
900 trap->ttyp != PIT && trap->ttyp != SPIKED_PIT)
901 || !Can_fall_thru(&u.uz) || !trap->tseen) {
902
903 if (flags.autodig && !flags.nopick &&
904 uwep && is_pick(uwep)) {
905 return use_pick_axe2(uwep);
906 } else {
907 You_cant("go down here.");
908 return(0);
909 }
910 }
911 }
912 if(u.ustuck) {
913 You("are %s, and cannot go down.",
914 !u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
915 "swallowed" : "engulfed");
916 return(1);
917 }
918 if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
919 You("are standing at the gate to Gehennom.");
920 pline("Unspeakable cruelty and harm lurk down there.");
921 if (yn("Are you sure you want to enter?") != 'y')
922 return(0);
923 else pline("So be it.");
924 u.uevent.gehennom_entered = 1; /* don't ask again */
925 }
926
927 if(!next_to_u()) {
928 You("are held back by your pet!");
929 return(0);
930 }
931
932 if (trap) {
933 if (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) {
934 if (u.utrap && (u.utraptype == TT_PIT)) {
935 if (flags.autodig && !flags.nopick &&
936 uwep && is_pick(uwep)) {
937 return use_pick_axe2(uwep);
938 } else {
939 You("are already in the pit."); /* YAFM needed */
940 }
941 } else {
942 u.utrap = 1;
943 u.utraptype = TT_PIT;
944 You("%s down into the pit.", locomotion(youmonst.data, "go"));
945 }
946 return(0);
947 } else {
948 You("%s %s.", locomotion(youmonst.data, "jump"),
949 trap->ttyp == HOLE ? "down the hole" : "through the trap door");
950 }
951 }
952
953 if (trap && Is_stronghold(&u.uz)) {
954 goto_hell(FALSE, TRUE);
955 } else {
956 at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
957 next_level(!trap);
958 at_ladder = FALSE;
959 }
960 return(1);
961 }
962
963 int
doup()964 doup()
965 {
966 if( (u.ux != xupstair || u.uy != yupstair)
967 && (!xupladder || u.ux != xupladder || u.uy != yupladder)
968 && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
969 || !sstairs.up)
970 ) {
971 You_cant("go up here.");
972 return(0);
973 }
974 #ifdef STEED
975 if (u.usteed && !u.usteed->mcanmove) {
976 pline("%s won't move!", Monnam(u.usteed));
977 return(0);
978 } else if (u.usteed && u.usteed->meating) {
979 pline("%s is still eating.", Monnam(u.usteed));
980 return(0);
981 } else
982 #endif
983 if(u.ustuck) {
984 You("are %s, and cannot go up.",
985 !u.uswallow ? "being held" : is_animal(u.ustuck->data) ?
986 "swallowed" : "engulfed");
987 return(1);
988 }
989 if(near_capacity() > SLT_ENCUMBER) {
990 /* No levitation check; inv_weight() already allows for it */
991 Your("load is too heavy to climb the %s.",
992 levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
993 return(1);
994 }
995 if(ledger_no(&u.uz) == 1) {
996 if (yn("Beware, there will be no return! Still climb?") != 'y')
997 return(0);
998 }
999 if(!next_to_u()) {
1000 You("are held back by your pet!");
1001 return(0);
1002 }
1003 at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
1004 prev_level(TRUE);
1005 at_ladder = FALSE;
1006 return(1);
1007 }
1008
1009 d_level save_dlevel = {0, 0};
1010
1011 /* check that we can write out the current level */
1012 STATIC_OVL int
currentlevel_rewrite()1013 currentlevel_rewrite()
1014 {
1015 register int fd;
1016 char whynot[BUFSZ];
1017
1018 /* since level change might be a bit slow, flush any buffered screen
1019 * output (like "you fall through a trap door") */
1020 mark_synch();
1021
1022 fd = create_levelfile(ledger_no(&u.uz), whynot);
1023 if (fd < 0) {
1024 /*
1025 * This is not quite impossible: e.g., we may have
1026 * exceeded our quota. If that is the case then we
1027 * cannot leave this level, and cannot save either.
1028 * Another possibility is that the directory was not
1029 * writable.
1030 */
1031 pline("%s", whynot);
1032 return -1;
1033 }
1034
1035 #ifdef MFLOPPY
1036 if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
1037 (void) close(fd);
1038 delete_levelfile(ledger_no(&u.uz));
1039 pline("UnNetHack is out of disk space for making levels!");
1040 You("can save, quit, or continue playing.");
1041 return -1;
1042 }
1043 #endif
1044 return fd;
1045 }
1046
1047 #ifdef INSURANCE
1048 void
save_currentstate()1049 save_currentstate()
1050 {
1051 int fd;
1052
1053 if (flags.ins_chkpt) {
1054 /* write out just-attained level, with pets and everything */
1055 fd = currentlevel_rewrite();
1056 if(fd < 0) return;
1057 bufon(fd);
1058 savelev(fd,ledger_no(&u.uz), WRITE_SAVE);
1059 bclose(fd);
1060 }
1061
1062 /* write out non-level state */
1063 savestateinlock();
1064 }
1065 #endif
1066
1067 /*
1068 static boolean
1069 badspot(x, y)
1070 register xchar x, y;
1071 {
1072 return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR &&
1073 levl[x][y].typ != CORR) || MON_AT(x, y));
1074 }
1075 */
1076
1077 #ifdef BLACKMARKET
1078 d_level new_dlevel = {0, 0};
1079 #endif
1080
1081 void
goto_level(newlevel,at_stairs,falling,portal)1082 goto_level(newlevel, at_stairs, falling, portal)
1083 d_level *newlevel;
1084 boolean at_stairs, falling, portal;
1085 {
1086 int fd, l_idx;
1087 xchar new_ledger;
1088 boolean cant_go_back,
1089 up = (depth(newlevel) < depth(&u.uz)),
1090 newdungeon = (u.uz.dnum != newlevel->dnum),
1091 was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
1092 familiar = FALSE;
1093 boolean new = FALSE; /* made a new level? */
1094 struct monst *mtmp;
1095 char whynot[BUFSZ];
1096
1097 if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
1098 newlevel->dlevel = dunlevs_in_dungeon(newlevel);
1099 if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
1100 if (u.uhave.amulet) {
1101 #ifdef RANDOMIZED_PLANES
1102 pline("Well done, mortal!");
1103 pline("But now thou must face the final Test...");
1104 pline("Prove thyself worthy or perish!");
1105 assign_level(newlevel, get_first_elemental_plane());
1106 #else
1107 assign_level(newlevel, &earth_level);
1108 #endif
1109 }
1110 else return;
1111 }
1112 new_ledger = ledger_no(newlevel);
1113 if (new_ledger <= 0)
1114 done(ESCAPED); /* in fact < 0 is impossible */
1115
1116 #ifdef BLACKMARKET
1117 assign_level(&new_dlevel, newlevel);
1118 #endif
1119
1120 /* Prevent the player from going past the first quest level unless
1121 * (s)he has been given the go-ahead by the leader.
1122 */
1123 if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
1124 pline("A mysterious force prevents you from descending.");
1125 return;
1126 }
1127
1128 if (on_level(newlevel, &u.uz)) return; /* this can happen */
1129
1130 fd = currentlevel_rewrite();
1131 if (fd < 0) return;
1132
1133 if (falling) /* assuming this is only trap door or hole */
1134 impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
1135
1136 check_special_room(TRUE); /* probably was a trap door */
1137 if (Punished) unplacebc();
1138 u.utrap = 0; /* needed in level_tele */
1139 fill_pit(u.ux, u.uy);
1140 u.ustuck = 0; /* idem */
1141 u.uinwater = 0;
1142 u.uundetected = 0; /* not hidden, even if means are available */
1143 keepdogs(FALSE);
1144 if (u.uswallow) /* idem */
1145 u.uswldtim = u.uswallow = 0;
1146 recalc_mapseen(); /* recalculate map overview before we leave the level */
1147 /*
1148 * We no longer see anything on the level. Make sure that this
1149 * follows u.uswallow set to null since uswallow overrides all
1150 * normal vision.
1151 */
1152 vision_recalc(2);
1153
1154 /*
1155 * Save the level we're leaving. If we're entering the endgame,
1156 * we can get rid of all existing levels because they cannot be
1157 * reached any more. We still need to use savelev()'s cleanup
1158 * for the level being left, to recover dynamic memory in use and
1159 * to avoid dangling timers and light sources.
1160 */
1161 cant_go_back = (newdungeon && In_endgame(newlevel));
1162 if (!cant_go_back) {
1163 update_mlstmv(); /* current monsters are becoming inactive */
1164 bufon(fd); /* use buffered output */
1165 }
1166 savelev(fd, ledger_no(&u.uz),
1167 cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
1168 bclose(fd);
1169 if (cant_go_back) {
1170 /* discard unreachable levels; keep #0 */
1171 for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
1172 delete_levelfile(l_idx);
1173 }
1174
1175 #ifdef REINCARNATION
1176 if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
1177 assign_rogue_graphics(Is_rogue_level(newlevel));
1178 #endif
1179 #ifdef USE_TILES
1180 substitute_tiles(newlevel);
1181 #endif
1182 /* record this level transition as a potential seen branch unless using
1183 * some non-standard means of transportation (level teleport).
1184 */
1185 if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum))
1186 recbranch_mapseen(&u.uz, newlevel);
1187 assign_level(&u.uz0, &u.uz);
1188 assign_level(&u.uz, newlevel);
1189 assign_level(&u.utolev, newlevel);
1190 u.utotype = 0;
1191 if (dunlev_reached(&u.uz) < dunlev(&u.uz))
1192 dunlev_reached(&u.uz) = dunlev(&u.uz);
1193 reset_rndmonst(NON_PM); /* u.uz change affects monster generation */
1194
1195 /* set default level change destination areas */
1196 /* the special level code may override these */
1197 (void) memset((genericptr_t) &updest, 0, sizeof updest);
1198 (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
1199
1200 if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
1201 /* entering this level for first time; make it now */
1202 if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) {
1203 impossible("goto_level: returning to discarded level?");
1204 level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED);
1205 }
1206 mklev();
1207 new = TRUE; /* made the level */
1208 } else {
1209 /* returning to previously visited level; reload it */
1210 fd = open_levelfile(new_ledger, whynot);
1211 if (fd < 0) {
1212 pline("%s", whynot);
1213 pline("Probably someone removed it.");
1214 killer = whynot;
1215 done(TRICKED);
1216 /* we'll reach here if running in wizard mode */
1217 error("Cannot continue this game.");
1218 }
1219 minit(); /* ZEROCOMP */
1220 getlev(fd, hackpid, new_ledger, FALSE);
1221 (void) close(fd);
1222 }
1223 /* do this prior to level-change pline messages */
1224 vision_reset(); /* clear old level's line-of-sight */
1225 vision_full_recalc = 0; /* don't let that reenable vision yet */
1226 flush_screen(-1); /* ensure all map flushes are postponed */
1227
1228 if (portal && !In_endgame(&u.uz)) {
1229 /* find the portal on the new level */
1230 register struct trap *ttrap;
1231
1232 for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
1233 if (ttrap->ttyp == MAGIC_PORTAL) break;
1234
1235 if (!ttrap) panic("goto_level: no corresponding portal!");
1236 seetrap(ttrap);
1237 u_on_newpos(ttrap->tx, ttrap->ty);
1238 } else if (at_stairs && !In_endgame(&u.uz)) {
1239 if (up) {
1240 if (at_ladder) {
1241 u_on_newpos(xdnladder, ydnladder);
1242 } else {
1243 if (newdungeon) {
1244 if (Is_stronghold(&u.uz)) {
1245 register xchar x, y;
1246 int trycnt = 0;
1247
1248 do {
1249 do {
1250 x = rn1((updest.hx - updest.lx)+1, updest.lx);
1251 y = rn1((updest.hy - updest.ly)+1, updest.ly);
1252 } while ((x < updest.nlx ||
1253 x > updest.nhx) &&
1254 (y < updest.nly ||
1255 y > updest.nhy));
1256 } while ((occupied(x, y) ||
1257 IS_STWALL(levl[x][y].typ)) && (trycnt++ < 1000));
1258 if (trycnt >= 1000) warning("castle: placement failed to find good position"); /* TODO: change impossible() to warning() */
1259 u_on_newpos(x, y);
1260 } else u_on_sstairs();
1261 } else u_on_dnstairs();
1262 }
1263 /* Remove bug which crashes with levitation/punishment KAA */
1264 if (Punished && !Levitation) {
1265 pline("With great effort you climb the %s.",
1266 at_ladder ? "ladder" : "stairs");
1267 } else if (at_ladder)
1268 You("climb up the ladder.");
1269 } else { /* down */
1270 if (at_ladder) {
1271 u_on_newpos(xupladder, yupladder);
1272 } else {
1273 if (newdungeon) u_on_sstairs();
1274 else u_on_upstairs();
1275 }
1276 if (u.dz && Flying)
1277 You("fly down along the %s.",
1278 at_ladder ? "ladder" : "stairs");
1279 else if (u.dz &&
1280 (near_capacity() > UNENCUMBERED || Punished || Fumbling)) {
1281 You("fall down the %s.", at_ladder ? "ladder" : "stairs");
1282 if (Punished) {
1283 drag_down();
1284 if (carried(uball)) {
1285 if (uwep == uball)
1286 setuwep((struct obj *)0);
1287 if (uswapwep == uball)
1288 setuswapwep((struct obj *)0);
1289 if (uquiver == uball)
1290 setuqwep((struct obj *)0);
1291 freeinv(uball);
1292 }
1293 }
1294 #ifdef STEED
1295 /* falling off steed has its own losehp() call */
1296 if (u.usteed)
1297 dismount_steed(DISMOUNT_FELL);
1298 else
1299 #endif
1300 losehp(rnd(3), "falling downstairs", KILLED_BY);
1301 selftouch("Falling, you");
1302 } else if (u.dz && at_ladder)
1303 You("climb down the ladder.");
1304 }
1305 } else { /* trap door or level_tele or In_endgame */
1306 if (was_in_W_tower && On_W_tower_level(&u.uz))
1307 /* Stay inside the Wizard's tower when feasible. */
1308 /* Note: up vs down doesn't really matter in this case. */
1309 place_lregion(dndest.nlx, dndest.nly,
1310 dndest.nhx, dndest.nhy,
1311 0,0, 0,0, LR_DOWNTELE, (d_level *) 0);
1312 else if (up)
1313 place_lregion(updest.lx, updest.ly,
1314 updest.hx, updest.hy,
1315 updest.nlx, updest.nly,
1316 updest.nhx, updest.nhy,
1317 LR_UPTELE, (d_level *) 0);
1318 else
1319 place_lregion(dndest.lx, dndest.ly,
1320 dndest.hx, dndest.hy,
1321 dndest.nlx, dndest.nly,
1322 dndest.nhx, dndest.nhy,
1323 LR_DOWNTELE, (d_level *) 0);
1324 if (falling) {
1325 if (Punished) ballfall();
1326 selftouch("Falling, you");
1327 }
1328 }
1329
1330 if (Punished) placebc();
1331 obj_delivery(); /* before killing geno'd monsters' eggs */
1332 losedogs();
1333 kill_genocided_monsters(); /* for those wiped out while in limbo */
1334 /*
1335 * Expire all timers that have gone off while away. Must be
1336 * after migrating monsters and objects are delivered
1337 * (losedogs and obj_delivery).
1338 */
1339 run_timers();
1340
1341 initrack();
1342
1343 if ((mtmp = m_at(u.ux, u.uy)) != 0
1344 #ifdef STEED
1345 && mtmp != u.usteed
1346 #endif
1347 ) {
1348 /* There's a monster at your target destination; it might be one
1349 which accompanied you--see mon_arrive(dogmove.c)--or perhaps
1350 it was already here. Randomly move you to an adjacent spot
1351 or else the monster to any nearby location. Prior to 3.3.0
1352 the latter was done unconditionally. */
1353 coord cc;
1354
1355 if (!rn2(2) &&
1356 enexto(&cc, u.ux, u.uy, youmonst.data) &&
1357 distu(cc.x, cc.y) <= 2)
1358 u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/
1359 else
1360 mnexto(mtmp);
1361
1362 if ((mtmp = m_at(u.ux, u.uy)) != 0) {
1363 impossible("mnexto failed (do.c)?");
1364 (void) rloc(mtmp, FALSE);
1365 }
1366 }
1367
1368 /* initial movement of bubbles just before vision_recalc */
1369 if (Is_waterlevel(&u.uz))
1370 movebubbles();
1371
1372 if (level_info[new_ledger].flags & FORGOTTEN) {
1373 forget_map(ALL_MAP); /* forget the map */
1374 forget_traps(); /* forget all traps too */
1375 familiar = TRUE;
1376 level_info[new_ledger].flags &= ~FORGOTTEN;
1377 }
1378
1379 /* Reset the screen. */
1380 vision_reset(); /* reset the blockages */
1381 docrt(); /* does a full vision recalc */
1382 flush_screen(-1);
1383
1384 /*
1385 * Move all plines beyond the screen reset.
1386 */
1387
1388 /* give room entrance message, if any */
1389 check_special_room(FALSE);
1390
1391 /* Check whether we just entered Gehennom. */
1392 if (!In_hell(&u.uz0) && Inhell) {
1393 if (Is_valley(&u.uz)) {
1394 You("arrive at the Valley of the Dead...");
1395 pline_The("odor of burnt flesh and decay pervades the air.");
1396 #ifdef MICRO
1397 display_nhwindow(WIN_MESSAGE, FALSE);
1398 #endif
1399 You_hear("groans and moans everywhere.");
1400 } else pline("It is hot here. You smell smoke...");
1401
1402 #ifdef RECORD_ACHIEVE
1403 achieve.enter_gehennom = 1;
1404 #ifdef LIVELOGFILE
1405 livelog_achieve_update();
1406 #endif
1407 #endif
1408 }
1409
1410 if (familiar) {
1411 static const char * const fam_msgs[4] = {
1412 "You have a sense of deja vu.",
1413 "You feel like you've been here before.",
1414 "This place %s familiar...",
1415 0 /* no message */
1416 };
1417 static const char * const halu_fam_msgs[4] = {
1418 "Whoa! Everything %s different.",
1419 "You are surrounded by twisty little passages, all alike.",
1420 "Gee, this %s like uncle Conan's place...",
1421 0 /* no message */
1422 };
1423 const char *mesg;
1424 char buf[BUFSZ];
1425 int which = rn2(4);
1426
1427 if (Hallucination)
1428 mesg = halu_fam_msgs[which];
1429 else
1430 mesg = fam_msgs[which];
1431 if (mesg && index(mesg, '%')) {
1432 Sprintf(buf, mesg, !Blind ? "looks" : "seems");
1433 mesg = buf;
1434 }
1435 if (mesg) pline(mesg);
1436 }
1437
1438 #ifdef REINCARNATION
1439 if (new && Is_rogue_level(&u.uz))
1440 You("enter what seems to be an older, more primitive world.");
1441 #endif
1442 if (new && Hallucination &&
1443 Role_if(PM_ARCHEOLOGIST) &&
1444 Is_juiblex_level(&u.uz))
1445 pline("Ahh, Venice.");
1446
1447 /* Final confrontation */
1448 if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet)
1449 resurrect();
1450 if (newdungeon && In_V_tower(&u.uz) && In_hell(&u.uz0))
1451 pline_The("heat and smoke are gone.");
1452
1453 /* the message from your quest leader */
1454 if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
1455 !(u.uevent.qexpelled || u.uevent.qcompleted || quest_status.leader_is_dead)) {
1456 if (u.uprops[TELEPAT].blocked) {
1457 if (uarmh)
1458 You("sense something being blocked by %s.", yname(uarmh));
1459 } else if (u.uevent.qcalled) {
1460 com_pager(Role_if(PM_ROGUE) ? 4 : 3);
1461 } else {
1462 com_pager(2);
1463 u.uevent.qcalled = TRUE;
1464 }
1465 }
1466
1467 /* once Croesus is dead, his alarm doesn't work any more */
1468 if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) {
1469 You("penetrated a high security area!");
1470 pline("An alarm sounds!");
1471 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1472 if (!DEADMONSTER(mtmp) && mtmp->msleeping) mtmp->msleeping = 0;
1473 }
1474
1475 #ifdef BLACKMARKET
1476 if (Is_blackmarket(&u.uz) && Conflict) {
1477 set_black_marketeer_angry();
1478 }
1479 #endif /* BLACKMARKET */
1480
1481 if (on_level(&u.uz, &astral_level))
1482 final_level();
1483 else
1484 onquest();
1485 assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
1486
1487 #ifdef INSURANCE
1488 save_currentstate();
1489 #endif
1490
1491 /* assume this will always return TRUE when changing level */
1492 (void) in_out_region(u.ux, u.uy);
1493 (void) pickup(1);
1494 #ifdef WHEREIS_FILE
1495 touch_whereis();
1496 #endif
1497 }
1498
1499 STATIC_OVL void
final_level()1500 final_level()
1501 {
1502 struct monst *mtmp;
1503 struct obj *otmp;
1504 coord mm;
1505 int i;
1506
1507 /* reset monster hostility relative to player */
1508 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
1509 if (!DEADMONSTER(mtmp)) reset_hostility(mtmp);
1510
1511 /* create some player-monsters */
1512 create_mplayers(rn1(4, 3), TRUE);
1513
1514 /* create a guardian angel next to player, if worthy */
1515 if (Conflict) {
1516 pline(
1517 "A voice booms: \"Thy desire for conflict shall be fulfilled!\"");
1518 for (i = rnd(4); i > 0; --i) {
1519 mm.x = u.ux;
1520 mm.y = u.uy;
1521 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
1522 (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1523 mm.x, mm.y, FALSE);
1524 }
1525
1526 } else if (u.ualign.record > 8) { /* fervent */
1527 pline("A voice whispers: \"Thou hast been worthy of me!\"");
1528 mm.x = u.ux;
1529 mm.y = u.uy;
1530 if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) {
1531 if ((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type,
1532 mm.x, mm.y, TRUE)) != 0) {
1533 if (!Blind)
1534 pline("An angel appears near you.");
1535 else
1536 You_feel("the presence of a friendly angel near you.");
1537 /* guardian angel -- the one case mtame doesn't
1538 * imply an edog structure, so we don't want to
1539 * call tamedog().
1540 */
1541 mtmp->mtame = 10;
1542 /* make him strong enough vs. endgame foes */
1543 mtmp->m_lev = rn1(8,15);
1544 mtmp->mhp = mtmp->mhpmax =
1545 d((int)mtmp->m_lev,10) + 30 + rnd(30);
1546 if ((otmp = select_hwep(mtmp)) == 0) {
1547 otmp = mksobj(SILVER_SABER, FALSE, FALSE);
1548 if (mpickobj(mtmp, otmp))
1549 panic("merged weapon?");
1550 }
1551 bless(otmp);
1552 if (otmp->spe < 4) otmp->spe += rnd(4);
1553 if ((otmp = which_armor(mtmp, W_ARMS)) == 0 ||
1554 otmp->otyp != SHIELD_OF_REFLECTION) {
1555 (void) mongets(mtmp, AMULET_OF_REFLECTION);
1556 m_dowear(mtmp, TRUE);
1557 }
1558 }
1559 }
1560 }
1561 }
1562
1563 static char *dfr_pre_msg = 0, /* pline() before level change */
1564 *dfr_post_msg = 0; /* pline() after level change */
1565
1566 /* change levels at the end of this turn, after monsters finish moving */
1567 void
schedule_goto(tolev,at_stairs,falling,portal_flag,pre_msg,post_msg)1568 schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
1569 d_level *tolev;
1570 boolean at_stairs, falling;
1571 int portal_flag;
1572 const char *pre_msg, *post_msg;
1573 {
1574 int typmask = 0100; /* non-zero triggers `deferred_goto' */
1575
1576 /* destination flags (`goto_level' args) */
1577 if (at_stairs) typmask |= 1;
1578 if (falling) typmask |= 2;
1579 if (portal_flag) typmask |= 4;
1580 if (portal_flag < 0) typmask |= 0200; /* flag for portal removal */
1581 u.utotype = typmask;
1582 /* destination level */
1583 assign_level(&u.utolev, tolev);
1584
1585 if (pre_msg)
1586 dfr_pre_msg = strcpy((char *)alloc(strlen(pre_msg) + 1), pre_msg);
1587 if (post_msg)
1588 dfr_post_msg = strcpy((char *)alloc(strlen(post_msg)+1), post_msg);
1589 }
1590
1591 /* handle something like portal ejection */
1592 void
deferred_goto()1593 deferred_goto()
1594 {
1595 if (!on_level(&u.uz, &u.utolev)) {
1596 d_level dest;
1597 int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
1598
1599 assign_level(&dest, &u.utolev);
1600 if (dfr_pre_msg) pline(dfr_pre_msg);
1601 goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4));
1602 if (typmask & 0200) { /* remove portal */
1603 struct trap *t = t_at(u.ux, u.uy);
1604
1605 if (t) {
1606 deltrap(t);
1607 newsym(u.ux, u.uy);
1608 }
1609 }
1610 if (dfr_post_msg) pline(dfr_post_msg);
1611 }
1612 u.utotype = 0; /* our caller keys off of this */
1613 if (dfr_pre_msg)
1614 free((genericptr_t)dfr_pre_msg), dfr_pre_msg = 0;
1615 if (dfr_post_msg)
1616 free((genericptr_t)dfr_post_msg), dfr_post_msg = 0;
1617 }
1618
1619 #endif /* OVL2 */
1620 #ifdef OVL3
1621
1622 /*
1623 * Return TRUE if we created a monster for the corpse. If successful, the
1624 * corpse is gone.
1625 */
1626 boolean
revive_corpse(corpse)1627 revive_corpse(corpse)
1628 struct obj *corpse;
1629 {
1630 struct monst *mtmp, *mcarry;
1631 boolean is_uwep, chewed;
1632 xchar where;
1633 char *cname, cname_buf[BUFSZ];
1634 struct obj *container = (struct obj *)0;
1635 int container_where = 0;
1636
1637 where = corpse->where;
1638 is_uwep = corpse == uwep;
1639 cname = eos(strcpy(cname_buf, "bite-covered "));
1640 Strcpy(cname, corpse_xname(corpse, TRUE));
1641 mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
1642
1643 if (where == OBJ_CONTAINED) {
1644 struct monst *mtmp2 = (struct monst *)0;
1645 container = corpse->ocontainer;
1646 mtmp2 = get_container_location(container, &container_where, (int *)0);
1647 /* container_where is the outermost container's location even if nested */
1648 if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2;
1649 }
1650 mtmp = revive(corpse); /* corpse is gone if successful */
1651
1652 if (mtmp) {
1653 chewed = (mtmp->mhp < mtmp->mhpmax);
1654 if (chewed) cname = cname_buf; /* include "bite-covered" prefix */
1655 switch (where) {
1656 case OBJ_INVENT:
1657 if (is_uwep)
1658 pline_The("%s writhes out of your grasp!", cname);
1659 else
1660 You_feel("squirming in your backpack!");
1661 break;
1662
1663 case OBJ_FLOOR:
1664 if (cansee(mtmp->mx, mtmp->my))
1665 pline("%s rises from the dead!", chewed ?
1666 Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1667 break;
1668
1669 case OBJ_MINVENT: /* probably a nymph's */
1670 if (cansee(mtmp->mx, mtmp->my)) {
1671 if (canseemon(mcarry))
1672 pline("Startled, %s drops %s as it revives!",
1673 mon_nam(mcarry), an(cname));
1674 else
1675 pline("%s suddenly appears!", chewed ?
1676 Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp));
1677 }
1678 break;
1679 case OBJ_CONTAINED:
1680 if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my) &&
1681 mcarry && canseemon(mcarry) && container) {
1682 char sackname[BUFSZ];
1683 Sprintf(sackname, "%s %s", s_suffix(mon_nam(mcarry)),
1684 xname(container));
1685 pline("%s writhes out of %s!", Amonnam(mtmp), sackname);
1686 } else if (container_where == OBJ_INVENT && container) {
1687 char sackname[BUFSZ];
1688 Strcpy(sackname, an(xname(container)));
1689 pline("%s %s out of %s in your pack!",
1690 Blind ? Something : Amonnam(mtmp),
1691 locomotion(mtmp->data,"writhes"),
1692 sackname);
1693 } else if (container_where == OBJ_FLOOR && container &&
1694 cansee(mtmp->mx, mtmp->my)) {
1695 char sackname[BUFSZ];
1696 Strcpy(sackname, an(xname(container)));
1697 pline("%s escapes from %s!", Amonnam(mtmp), sackname);
1698 }
1699 break;
1700 default:
1701 /* we should be able to handle the other cases... */
1702 impossible("revive_corpse: lost corpse @ %d", where);
1703 break;
1704 }
1705 return TRUE;
1706 }
1707 return FALSE;
1708 }
1709
1710 /* Revive the corpse via a timeout. */
1711 /*ARGSUSED*/
1712 void
revive_mon(arg,timeout)1713 revive_mon(arg, timeout)
1714 genericptr_t arg;
1715 long timeout;
1716 {
1717 struct obj *body = (struct obj *) arg;
1718
1719 /* if we succeed, the corpse is gone, otherwise, rot it away */
1720 if (!revive_corpse(body)) {
1721 if (is_rider(&mons[body->corpsenm]))
1722 You_feel("less hassled.");
1723 (void) start_timer(250L - (monstermoves-body->age),
1724 TIMER_OBJECT, ROT_CORPSE, arg);
1725 }
1726 }
1727
1728 int
donull()1729 donull()
1730 {
1731 return(1); /* Do nothing, but let other things happen */
1732 }
1733
1734 #endif /* OVL3 */
1735 #ifdef OVLB
1736
1737 STATIC_PTR int
wipeoff()1738 wipeoff()
1739 {
1740 if(u.ucreamed < 4) u.ucreamed = 0;
1741 else u.ucreamed -= 4;
1742 if (Blinded < 4) Blinded = 0;
1743 else Blinded -= 4;
1744 if (!Blinded) {
1745 pline("You've got the glop off.");
1746 u.ucreamed = 0;
1747 Blinded = 1;
1748 make_blinded(0L,TRUE);
1749 return(0);
1750 } else if (!u.ucreamed) {
1751 Your("%s feels clean now.", body_part(FACE));
1752 return(0);
1753 }
1754 return(1); /* still busy */
1755 }
1756
1757 int
dowipe()1758 dowipe()
1759 {
1760 if(u.ucreamed) {
1761 static NEARDATA char buf[39];
1762
1763 Sprintf(buf, "wiping off your %s", body_part(FACE));
1764 set_occupation(wipeoff, buf, 0);
1765 /* Not totally correct; what if they change back after now
1766 * but before they're finished wiping?
1767 */
1768 return(1);
1769 }
1770 Your("%s is already clean.", body_part(FACE));
1771 return(1);
1772 }
1773
1774 void
set_wounded_legs(side,timex)1775 set_wounded_legs(side, timex)
1776 register long side;
1777 register int timex;
1778 {
1779 /* KMH -- STEED
1780 * If you are riding, your steed gets the wounded legs instead.
1781 * You still call this function, but don't lose hp.
1782 * Caller is also responsible for adjusting messages.
1783 */
1784
1785 if(!Wounded_legs) {
1786 ATEMP(A_DEX)--;
1787 flags.botl = 1;
1788 }
1789
1790 if(!Wounded_legs || (HWounded_legs & TIMEOUT))
1791 HWounded_legs = timex;
1792 EWounded_legs = side;
1793 (void)encumber_msg();
1794 }
1795
1796 void
heal_legs()1797 heal_legs()
1798 {
1799 if(Wounded_legs) {
1800 if (ATEMP(A_DEX) < 0) {
1801 ATEMP(A_DEX)++;
1802 flags.botl = 1;
1803 }
1804
1805 #ifdef STEED
1806 if (!u.usteed)
1807 #endif
1808 {
1809 /* KMH, intrinsics patch */
1810 if((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) {
1811 Your("%s feel somewhat better.",
1812 makeplural(body_part(LEG)));
1813 } else {
1814 Your("%s feels somewhat better.",
1815 body_part(LEG));
1816 }
1817 }
1818 HWounded_legs = EWounded_legs = 0;
1819 }
1820 (void)encumber_msg();
1821 }
1822
1823 #endif /* OVLB */
1824
1825 /*do.c*/
1826