home *** CD-ROM | disk | FTP | other *** search
- /* SCCS Id: @(#)do.c 3.1 92/11/11 */
- /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
- /* NetHack may be freely redistributed. See license for details. */
-
- /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
-
- #include "hack.h"
- #include "lev.h"
-
- #include <errno.h>
- #ifdef _MSC_VER /* MSC 6.0 defines errno quite differently */
- # if (_MSC_VER >= 600)
- # define SKIP_ERRNO
- # endif
- #endif
- #ifndef SKIP_ERRNO
- extern int errno;
- #endif
-
- #ifdef MFLOPPY
- extern struct finfo fileinfo[];
- #else
- extern boolean level_exists[];
- #endif
-
- #ifdef SINKS
- # ifdef OVLB
- static void FDECL(trycall, (struct obj *));
- # endif /* OVLB */
- STATIC_DCL void FDECL(dosinkring, (struct obj *));
- #endif /* SINKS */
-
- STATIC_PTR int FDECL(drop, (struct obj *));
- STATIC_PTR int NDECL(wipeoff);
-
- #ifdef OVL2
- static int NDECL(currentlevel_rewrite);
- /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
- #endif
-
- #ifdef OVLB
-
- static const char NEARDATA drop_types[] =
- { ALLOW_COUNT, GOLD_CLASS, ALL_CLASSES, 0 };
-
- int
- dodrop()
- {
- int result;
-
- if (*u.ushops) sellobj_state(TRUE);
- result = drop(getobj(drop_types, "drop"));
- if (*u.ushops) sellobj_state(FALSE);
- reset_occupations();
-
- return result;
- }
-
- #endif /* OVLB */
- #ifdef OVL0
-
- /* Called when a boulder is dropped, thrown, or pushed. If it ends up
- * in a pool, it either fills the pool up or sinks away. In either case,
- * it's gone for good... If the destination is not a pool, returns FALSE.
- */
- boolean
- boulder_hits_pool(otmp, rx, ry, pushing)
- struct obj *otmp;
- register int rx, ry;
- boolean pushing;
- {
- if (!otmp || otmp->otyp != BOULDER)
- impossible("Not a boulder?");
- else if (!Is_waterlevel(&u.uz) && (is_pool(rx,ry) || is_lava(rx,ry))) {
- boolean lava = is_lava(rx,ry), fills_up;
- const char *what = lava ? "lava" : "water";
- schar ltyp = levl[rx][ry].typ;
- int chance = rn2(10); /* water: 90%; lava: 10% */
- fills_up = lava ? chance == 0 : chance != 0;
-
- if (fills_up) {
- if (ltyp == DRAWBRIDGE_UP) {
- levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
- levl[rx][ry].drawbridgemask |= DB_FLOOR;
- } else
- levl[rx][ry].typ = ROOM;
-
- delallobj(rx, ry);
- newsym(rx,ry);
- if (pushing) {
- You("push %s into the %s.", the(xname(otmp)), what);
- if (flags.verbose && !Blind)
- pline("Now you can cross it!");
- /* no splashing in this case */
- }
- }
- if (!fills_up || !pushing) { /* splashing occurs */
- if (pushing ? !Blind : cansee(rx,ry))
- pline("There is a large splash as %s %s the %s.",
- the(xname(otmp)), fills_up ? "fills" : "falls into",
- lava ? "lava" : ltyp==POOL ? "pool" : "moat");
- else if (flags.soundok)
- You("hear a%s splash.", lava ? " sizzling" : "");
- wake_nearby();
-
- if (fills_up && u.uinwater && distu(rx,ry) == 0) {
- You("find yourself on dry land again!");
- u.uinwater = 0;
- } else if (lava && distu(rx,ry) <= 2) {
- You("are hit by molten lava%c",
- Fire_resistance ? '.' : '!');
- losehp(d((Fire_resistance ? 1 : 3), 6),
- "molten lava", KILLED_BY);
- } else if (!fills_up && flags.verbose &&
- (pushing ? !Blind : cansee(rx,ry)))
- pline("It sinks without a trace!");
- }
-
- /* boulder is now gone */
- if (pushing) delobj(otmp);
- else obfree(otmp, (struct obj *)0);
- return TRUE;
- }
- return FALSE;
- }
-
- /* Used for objects which sometimes do special things when dropped; must be
- * called with the object not in any chain. Returns 1 if the object is
- * gone.
- */
- boolean
- flooreffects(obj,x,y,verb)
- struct obj *obj;
- int x,y;
- const char *verb;
- {
- struct trap *t;
-
- if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE))
- return TRUE;
- else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 &&
- (t->ttyp==PIT || t->ttyp==SPIKED_PIT || t->ttyp==TRAPDOOR)) {
- struct monst *mtmp;
-
- delallobj(x, y);
- if(!Can_fall_thru(&u.uz) && t->ttyp == TRAPDOOR)
- return FALSE;
- if (((mtmp = m_at(x, y)) && mtmp->mtrapped) ||
- (u.utrap && x==u.ux && y==u.uy)) {
- /* u.utrap = 0; /* player remains trapped. See trap.c */
- if (*verb)
- pline("The boulder %ss into the pit%s.", verb,
- (mtmp)? "" : " with you");
- if (mtmp) {
- if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data))
- if (hmon(mtmp, obj, TRUE))
- return FALSE; /* still alive */
- else
- delallobj(x, y); /* treasure, corpse */
- } else
- #ifdef POLYSELF
- if (!passes_walls(uasmon) && !throws_rocks(uasmon))
- #endif
- {
- losehp(rnd(15), "squished under a boulder",
- NO_KILLER_PREFIX);
- return FALSE;
- }
- }
- if (*verb) {
- if (Blind) {
- if ((x == u.ux) && (y == u.uy))
- You("hear a CRASH! beneath you.");
- else
- You("hear the boulder %s.", verb);
- } else if (cansee(x, y)) {
- pline("The boulder %sfills a %s.",
- t->tseen ? "" : "triggers and ",
- t->ttyp == TRAPDOOR ?
- "trap door" : "pit");
- }
- }
- deltrap(t);
- obfree(obj, (struct obj *)0);
- newsym(x,y);
- return TRUE;
- }
- return FALSE;
- }
-
- #endif /* OVL0 */
- #ifdef OVLB
-
- void
- doaltarobj(obj) /* obj is an object dropped on an altar */
- register struct obj *obj;
- {
- if (Blind) return;
- if (obj->blessed || obj->cursed) {
- pline("There is %s flash as %s hit%s the altar.",
- an(Hallucination ? hcolor() :
- obj->blessed ? amber : Black),
- doname(obj),
- (obj->quan == 1L) ? "s" : "");
- if (!Hallucination) obj->bknown = 1;
- } else {
- pline("%s land%s on the altar.", Doname2(obj),
- (obj->quan == 1L) ? "s" : "");
- if (obj->otyp != GOLD_PIECE)
- obj->bknown = 1;
- }
- }
-
- #ifdef SINKS
- static
- void
- trycall(obj)
- register struct obj *obj;
- {
- if(!objects[obj->otyp].oc_name_known &&
- !objects[obj->otyp].oc_uname)
- docall(obj);
- }
-
- STATIC_OVL
- void
- dosinkring(obj) /* obj is a ring being dropped over a kitchen sink */
- register struct obj *obj;
- {
- register struct obj *otmp,*otmp2;
- register boolean ideed = TRUE;
-
- You("drop %s down the drain.", doname(obj));
- switch(obj->otyp) { /* effects that can be noticed without eyes */
- case RIN_SEARCHING:
- You("thought your %s got lost in the sink, but there it is!",
- xname(obj));
- dropx(obj);
- trycall(obj);
- return;
- case RIN_LEVITATION:
- pline("The sink quivers upward for a moment.");
- break;
- case RIN_POISON_RESISTANCE:
- #ifdef TUTTI_FRUTTI
- You("smell rotten %s.", makeplural(pl_fruit));
- #else
- You("smell rotten fruit.");
- #endif
- break;
- case RIN_AGGRAVATE_MONSTER:
- pline("Several flies buzz angrily around the sink.");
- break;
- case RIN_SHOCK_RESISTANCE:
- pline("Static electricity surrounds the sink.");
- break;
- case RIN_CONFLICT:
- You("hear loud noises coming from the drain.");
- break;
- case RIN_GAIN_STRENGTH:
- pline("The water flow seems %ser now.",
- (obj->spe<0) ? "weak" : "strong");
- break;
- case RIN_INCREASE_DAMAGE:
- pline("The water's force seems %ser now.",
- (obj->spe<0) ? "small" : "great");
- break;
- default:
- ideed = FALSE;
- break;
- }
- if(!Blind && !ideed) {
- ideed = TRUE;
- switch(obj->otyp) { /* effects that need eyes */
- case RIN_ADORNMENT:
- pline("The faucets flash brightly for a moment.");
- break;
- case RIN_REGENERATION:
- pline("The sink looks as good as new.");
- break;
- case RIN_INVISIBILITY:
- You("don't see anything happen to the sink.");
- break;
- case RIN_SEE_INVISIBLE:
- You("see some air in the sink.");
- break;
- case RIN_STEALTH:
- pline("The sink seems to blend into the floor for a moment.");
- break;
- case RIN_HUNGER:
- ideed = FALSE;
- for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
- otmp2 = otmp->nexthere;
- if(otmp != uball && otmp != uchain) {
- pline("Suddenly, %s vanishes from the sink!",
- doname(otmp));
- delobj(otmp);
- ideed = TRUE;
- }
- }
- break;
- case RIN_FIRE_RESISTANCE:
- pline("The hot water faucet flashes brightly for a moment.");
- break;
- case RIN_COLD_RESISTANCE:
- pline("The cold water faucet flashes brightly for a moment.");
- break;
- case RIN_PROTECTION_FROM_SHAPE_CHAN:
- pline("The sink looks nothing like a fountain.");
- break;
- case RIN_PROTECTION:
- pline("The sink glows %s for a moment.",
- Hallucination ? hcolor() :
- (obj->spe<0) ? Black : silver);
- break;
- case RIN_WARNING:
- pline("The sink glows %s for a moment.",
- Hallucination ? hcolor() : White);
- break;
- case RIN_TELEPORTATION:
- pline("The sink momentarily vanishes.");
- break;
- case RIN_TELEPORT_CONTROL:
- pline("The sink looks like it is being beamed aboard somewhere.");
- break;
- #ifdef POLYSELF
- case RIN_POLYMORPH:
- pline("The sink momentarily looks like a fountain.");
- break;
- case RIN_POLYMORPH_CONTROL:
- pline("The sink momentarily looks like a regularly erupting geyser.");
- break;
- #endif
- }
- }
- if(ideed)
- trycall(obj);
- else
- You("hear the ring bouncing down the drainpipe.");
- if (!rn2(20)) {
- pline("The sink backs up, leaving %s.", doname(obj));
- dropx(obj);
- }
- else
- useup(obj);
- }
- #endif
-
- #endif /* OVLB */
- #ifdef OVL0
-
- /* some common tests when trying to drop or throw items */
- boolean
- canletgo(obj,word)
- register struct obj *obj;
- register const char *word;
- {
- if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){
- if (*word)
- Norep("You cannot %s something you are wearing.",word);
- return(FALSE);
- }
- if (obj->otyp == LOADSTONE && obj->cursed) {
- if (*word)
- pline("For some reason, you cannot %s the stone%s!",
- word, plur(obj->quan));
- /* Kludge -- see invent.c */
- if (obj->corpsenm) {
- struct obj *otmp;
-
- otmp = obj;
- obj = obj->nobj;
- obj->quan += otmp->quan;
- obj->owt = weight(obj);
- freeinv(otmp);
- obfree(otmp, obj);
- }
- obj->bknown = 1;
- return(FALSE);
- }
- #ifdef WALKIES
- if (obj->otyp == LEASH && obj->leashmon != 0) {
- if (*word)
- pline ("The leash is tied around your %s.",
- body_part(HAND));
- return(FALSE);
- }
- #endif
- return(TRUE);
- }
-
- STATIC_PTR
- int
- drop(obj)
- register struct obj *obj;
- {
- if(!obj) return(0);
- if(!canletgo(obj,"drop"))
- return(0);
- if(obj == uwep) {
- if(welded(uwep)) {
- weldmsg(obj, FALSE);
- return(0);
- }
- setuwep((struct obj *)0);
- if(uwep) return 0; /* lifesaved and rewielded */
- }
- #ifdef SINKS
- if((obj->oclass == RING_CLASS) && IS_SINK(levl[u.ux][u.uy].typ)
- && !u.uswallow) {
- dosinkring(obj);
- return(1);
- }
- #endif
- if (IS_ALTAR(levl[u.ux][u.uy].typ) && !u.uswallow) {
- doaltarobj(obj); /* set bknown */
- } else
- if(flags.verbose) You("drop %s.", doname(obj));
- dropx(obj);
- return(1);
- }
-
- /* Called in several places - should not produce texts */
- void
- dropx(obj)
- register struct obj *obj;
- {
- /* Money is *not* in our inventory */
- if (obj->otyp != GOLD_PIECE) freeinv(obj);
- (void) snuff_candle(obj);
- if(!u.uswallow && obj != uball &&
- ship_object(obj, u.ux, u.uy, FALSE)) return;
- dropy(obj);
- }
-
- void
- dropy(obj)
- register struct obj *obj;
- {
- if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return;
- if(obj->otyp == CRYSKNIFE)
- obj->otyp = WORM_TOOTH;
- /* uswallow check done by GAN 01/29/87 */
- if(u.uswallow) {
- if (obj->otyp == GOLD_PIECE) {
- u.ustuck->mgold += obj->quan;
- delobj(obj);
- } else if (obj != uball) { /* mon doesn't pick up ball */
- (void) snuff_candle(obj); /* security. it's never lit */
- mpickobj(u.ustuck,obj);
- }
- } else {
- (void) snuff_candle(obj);
- obj->nobj = fobj;
- fobj = obj;
- place_object(obj, u.ux, u.uy);
- if (obj == uball)
- drop_ball(u.ux,u.uy);
- else
- sellobj(obj, u.ux, u.uy);
- stackobj(obj);
- if(Blind && Levitation)
- map_object(obj, 0);
- newsym(u.ux,u.uy); /* remap location under self */
- }
- }
-
- /* drop several things */
- int
- doddrop()
- {
- int result;
-
- if (*u.ushops) sellobj_state(TRUE);
- result = ggetobj("drop", drop, 0);
- if (*u.ushops) sellobj_state(FALSE);
- reset_occupations();
-
- return result;
- }
-
- #endif /* OVL0 */
- #ifdef OVL2
-
- /* on a ladder, used in goto_level */
- static boolean NEARDATA at_ladder = FALSE;
-
- int
- dodown()
- {
- struct trap *trap = 0;
-
- if( (u.ux != xdnstair || u.uy != ydnstair)
- && (!xdnladder || u.ux != xdnladder || u.uy != ydnladder)
- && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
- || sstairs.up)
- ) {
- if (!(trap = t_at(u.ux,u.uy)) || trap->ttyp != TRAPDOOR
- || !Can_fall_thru(&u.uz) || !trap->tseen) {
- You("can't go down here.");
- return(0);
- }
- }
- if(u.ustuck) {
- You("are being held, and cannot go down.");
- return(1);
- }
- if(Levitation) {
- pline("You're floating high above the %s.",
- levl[u.ux][u.uy].typ == STAIRS ? "stairs" :
- levl[u.ux][u.uy].typ == LADDER ? "ladder" :
- "trap door");
- return(0);
- }
- if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
- You("are standing at the gate to Gehennom.");
- pline("Unspeakable cruelty and harm lurk down there.");
- if (yn("Are you sure you want to enter?") != 'y')
- return(0);
- else pline("So be it.");
- u.uevent.gehennom_entered = 1; /* don't ask again */
- }
-
- #ifdef WALKIES
- if(!next_to_u()) {
- You("are held back by your pet!");
- return(0);
- }
- #endif
- if (trap)
- #ifdef POLYSELF
- You("%s into the trap door.", locomotion(uasmon, "jump"));
- #else
- You("jump into the trap door.");
- #endif
- if (levl[u.ux][u.uy].typ == LADDER) at_ladder = TRUE;
- next_level(!trap);
- at_ladder = FALSE;
- return(1);
- }
-
- int
- doup()
- {
- if( (u.ux != xupstair || u.uy != yupstair)
- && (!xupladder || u.ux != xupladder || u.uy != yupladder)
- && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
- || !sstairs.up)
- ) {
- You("can't go up here.");
- return(0);
- }
- if(u.ustuck) {
- You("are being held, and cannot go up.");
- return(1);
- }
- if(near_capacity() > SLT_ENCUMBER) {
- /* No levitation check; inv_weight() already allows for it */
- Your("load is too heavy to climb the %s.",
- levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
- return(1);
- }
- if(ledger_no(&u.uz) == 1) {
- if (yn("Beware, there will be no return! Still climb?") != 'y')
- return(0);
- }
- #ifdef WALKIES
- if(!next_to_u()) {
- You("are held back by your pet!");
- return(0);
- }
- #endif
- if (levl[u.ux][u.uy].typ == LADDER) at_ladder = TRUE;
- prev_level(TRUE);
- at_ladder = FALSE;
- return(1);
- }
-
- d_level save_dlevel = {0, 0};
-
- /* check that we can write out the current level */
- static int
- currentlevel_rewrite()
- {
- register int fd;
-
- fd = create_levelfile(ledger_no(&u.uz));
-
- if(fd < 0) {
- /*
- * This is not quite impossible: e.g., we may have
- * exceeded our quota. If that is the case then we
- * cannot leave this level, and cannot save either.
- * Another possibility is that the directory was not
- * writable.
- */
- pline("Cannot create level file for level %d.",
- ledger_no(&u.uz));
- return -1;
- }
-
- #ifdef MFLOPPY
- if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
- (void) close(fd);
- delete_levelfile(ledger_no(&u.uz));
- pline("NetHack is out of disk space for making levels!");
- You("can save, quit, or continue playing.");
- return -1;
- }
- #endif
- return fd;
- }
-
- #ifdef INSURANCE
- void
- save_currentstate()
- {
- int fd;
-
- if (flags.ins_chkpt) {
- /* write out just-attained level, with pets and everything */
- fd = currentlevel_rewrite();
- if(fd < 0) return;
- bufon(fd);
- savelev(fd,ledger_no(&u.uz), WRITE_SAVE);
- bclose(fd);
- }
-
- /* write out non-level state */
- savestateinlock();
- }
- #endif
-
- /*
- static boolean
- badspot(x, y)
- register xchar x, y;
- {
- return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR &&
- levl[x][y].typ != CORR) || MON_AT(x, y));
- }
- */
-
- void
- goto_level(newlevel, at_stairs, falling, portal)
- d_level *newlevel;
- register boolean at_stairs, falling, portal;
- {
- register int fd;
- register boolean up = (depth(newlevel) < depth(&u.uz));
- register boolean newdungeon = (u.uz.dnum != newlevel->dnum);
- #ifdef REINCARNATION
- int new = 0; /* made a new level? */
- #endif
-
- if(dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
- newlevel->dlevel = dunlevs_in_dungeon(newlevel);
- if(newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
- if(u.uhave.amulet)
- assign_level(newlevel, &earth_level);
- else return;
- }
- if(ledger_no(newlevel) <= 0)
- done(ESCAPED); /* in fact < 0 is impossible */
- /* If you have the amulet and are trying to get out of Hell, going
- * up a set of stairs sometimes does some very strange things!
- */
- if(Inhell && up && !newdungeon && u.uhave.amulet &&
- (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) {
- if(!rn2(4)) {
- if(!u.ualign.type) { /* neutral */
- if(rn2(2)) assign_level(newlevel, &u.uz);
- else assign_rnd_level(newlevel, &u.uz, rnd(3));
- } else if(u.ualign.type == A_LAWFUL) { /* lawful */
- assign_rnd_level(newlevel, &u.uz, rnd(3));
- } else assign_level(newlevel, &u.uz); /* chaotic */
- }
- pline("A mysterious force momentarily surrounds you...");
- if(ledger_no(newlevel) < 1) assign_level(newlevel, &u.uz);
- if(on_level(newlevel, &u.uz)) {
- (void) safe_teleds();
- #ifdef WALKIES
- (void) next_to_u();
- #endif
- return;
- }
- }
- #ifdef MULDGN
- /* Prevent the player from going past the first quest level unless
- * (s)he has been given the go-ahead by the leader.
- */
- if(on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
-
- pline("A mysterious force prevents you from descending.");
- return;
- }
- #endif
- if(on_level(newlevel, &u.uz)) return; /* this can happen */
-
- fd = currentlevel_rewrite();
- if(fd < 0) return;
-
- if (falling) /* assuming this is only trapdoor */
- impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel);
-
- check_special_room(TRUE); /* probably was a trap door */
- if(Punished) unplacebc();
- u.utrap = 0; /* needed in level_tele */
- fill_pit(u.ux, u.uy);
- u.ustuck = 0; /* idem */
- u.uinwater = 0;
- keepdogs();
- if(u.uswallow) /* idem */
- u.uswldtim = u.uswallow = 0;
- /*
- * We no longer see anything on the level. Make sure that this
- * follows u.uswallow set to null since uswallow overrides all
- * normal vision.
- */
- vision_recalc(2);
- bufon(fd);
- savelev(fd,ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
- bclose(fd);
-
- #ifdef REINCARNATION
- if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
- assign_rogue_graphics(Is_rogue_level(newlevel));
- #endif
- assign_level(&u.uz0, &u.uz);
- assign_level(&u.uz, newlevel);
- assign_level(&u.utolev, newlevel);
- u.utotype = 0;
- if(dunlev_reached(&u.uz) < dunlev(&u.uz))
- dunlev_reached(&u.uz) = dunlev(&u.uz);
-
- /* set default level change destination areas */
- /* the special level code may override these */
- (void) memset((genericptr_t) &updest, 0, sizeof updest);
- (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
-
- if(In_endgame(&u.uz) ||
- #ifdef MFLOPPY
- /* If the level has no .where yet, it hasn't been made */
- !fileinfo[ledger_no(&u.uz)].where) {
- #else
- !level_exists[ledger_no(&u.uz)]) {
- #endif
- mklev();
- #ifdef REINCARNATION
- new = 1; /* made the level */
- #endif
- } else {
- fd = open_levelfile(ledger_no(&u.uz));
- if (fd < 0) {
- pline("Cannot open file (#%d) for level %d (errno %d).",
- ledger_no(&u.uz), depth(&u.uz), errno);
- pline("Probably someone removed it.");
- done(TRICKED);
- }
- #ifdef ZEROCOMP
- minit();
- #endif
- getlev(fd, hackpid, ledger_no(&u.uz), FALSE);
- (void) close(fd);
- }
- #ifdef MULDGN
- quest_init(); /* re-initialize */
- #endif
-
- if(portal && !In_endgame(&u.uz)) {
- /* find the portal on the new level */
- register struct trap *ttrap;
-
- for(ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
- if(ttrap->ttyp == MAGIC_PORTAL) break;
-
- if(ttrap) {
- u.ux = ttrap->tx;
- u.uy = ttrap->ty;
- } else panic("goto_level: no corresponding portal!");
- } else if(at_stairs && !In_endgame(&u.uz)) {
- if(up) {
- if(at_ladder) {
- u.ux = xdnladder;
- u.uy = ydnladder;
- } else {
- if(newdungeon) {
- if(Is_stronghold(&u.uz)) {
- register xchar x, y;
-
- do {
- x = (COLNO - 2 - rnd(5));
- y = rn1(ROWNO - 4, 3);
- } while(occupied(x, y) ||
- IS_WALL(levl[x][y].typ));
- u.ux = x;
- u.uy = y;
- } else u_on_sstairs();
- } else u_on_dnstairs();
- }
- /* Remove bug which crashes with */
- /* levitation/punishment KAA */
- if(Punished) {
- if(!Levitation)
- pline("With great effort you climb the %s.",
- !at_ladder ? "stairs" : "ladder");
- placebc();
- }
- if(at_ladder && (!Punished || Levitation))
- You("climb up the ladder.");
- } else { /* down */
- if(at_ladder) {
- u.ux = xupladder;
- u.uy = yupladder;
- } else {
- if(newdungeon) u_on_sstairs();
- else u_on_upstairs();
- }
- if(at_stairs && u.dz && !up &&
- ((near_capacity()>UNENCUMBERED) || Punished || Fumbling)) {
- You("fall down the %s.",
- !at_ladder ? "stairs" : "ladder");
- if(Punished) {
- drag_down();
- if(carried(uball)) {
- if (uwep == uball)
- setuwep((struct obj *)0);
- if (uwep != uball)
- freeinv(uball);
- }
- placebc();
- }
- losehp(rnd(3), "falling downstairs", KILLED_BY);
- selftouch("Falling, you");
- }
- else if(at_ladder && u.dz)
- You("climb down the ladder.");
- }
- } else { /* trap door or level_tele or In_endgame */
- if(up)
- place_lregion(updest.lx, updest.ly,
- updest.hx, updest.hy,
- updest.nlx, updest.nly,
- updest.nhx, updest.nhy,
- LR_UPTELE, (d_level *) 0);
- else
- place_lregion(dndest.lx, dndest.ly,
- dndest.hx, dndest.hy,
- dndest.nlx, dndest.nly,
- dndest.nhx, dndest.nhy,
- LR_DOWNTELE, (d_level *) 0);
- if(Punished) {
- if(falling) ballfall();
- placebc();
- }
- if(falling)
- selftouch("Falling, you");
- }
-
- losedogs();
- obj_delivery();
- check_special_room(FALSE);
-
- initrack();
-
- if(MON_AT(u.ux, u.uy)) mnexto(m_at(u.ux, u.uy));
- if(MON_AT(u.ux, u.uy)) {
- impossible("mnexto failed (do.c)?");
- rloc(m_at(u.ux, u.uy));
- }
- remove_cadavers(&fobj); /* remove rotted meat (before seen) */
-
- /* initial movement of bubbles just before vision_recalc */
- if (Is_waterlevel(&u.uz))
- movebubbles();
-
- /* Reset the screen. */
- vision_reset(); /* reset the blockages */
- docrt(); /* does a full vision recalc */
-
- /* In Nethack 3.1, Gehennom starts after the stronghold. Moreover,
- * there are traps in the stronghold, that can send the player
- * to Gehennom (gnark, gnark)! So we have to test here:
- */
- if(!In_hell(&u.uz0) && Inhell) {
- if(Is_valley(newlevel)) {
- You("arrive at the Valley of the Dead...");
- pline("There is a smell of burnt flesh and decay here.");
- #ifdef MICRO
- display_nhwindow(WIN_MESSAGE, FALSE);
- #endif
- pline("The sounds of groans and moans fill the air.");
- } else pline("It is hot here. You smell smoke...");
- }
-
- #ifdef REINCARNATION
- /*
- * Move all plines beyond the screen reset.
- */
- if (new && Is_rogue_level(&u.uz))
- You("have entered what appears to be an older, more primitive world.");
- #endif
- /* Final confrontation */
- if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet &&
- flags.no_of_wizards == 0)
- resurrect();
- if (newdungeon && In_tower(&u.uz))
- pline("The heat and smoke are gone.");
- #ifdef MULDGN
- if(!In_quest(&u.uz0) && at_dgn_entrance("The Quest") &&
- !(u.uevent.qexpelled || u.uevent.qcompleted || leaderless()))
- com_pager(2); /* the message from the leader */
-
- if(Is_knox(&u.uz)) {
- register struct monst *mtmp;
-
- You("penetrated a high security area!");
- pline("An alarm sounds!");
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- if(mtmp->msleep) mtmp->msleep = 0;
- }
- #endif /* MULDGN */
- if(on_level(&u.uz, &astral_level)) {
- register struct monst *mtmp;
-
- /* reset monster hostility relative to player */
- for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
- reset_hostility(mtmp);
-
- /* create some player-monsters */
- create_mplayers(rn1(4, 3), TRUE);
-
- /* create a guardian angel next to player, if worthy */
- if (Conflict) {
- coord mm;
- int i = rnd(4);
- pline("A voice booms: \"Thy desire for conflict shall be rewarded!\"");
- while(i--) {
- mm.x = u.ux;
- mm.y = u.uy;
- if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL]))
- (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type,
- mm.x, mm.y, FALSE);
- }
-
- } else if(u.ualign.record > 3) {
- coord mm;
-
- pline("A voice whispers: \"Thou hast been worthy of me!\"");
- mm.x = u.ux;
- mm.y = u.uy;
- if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) {
- if((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type,
- mm.x, mm.y, TRUE)) != 0) {
- register struct obj *otmp =
- mksobj(SILVER_SABER, FALSE, FALSE);
-
- if(!Blind)
- pline("An angel appears near you.");
- else
- You("feel the presence of a friendly angel near you.");
- /* guardian angel -- the one case mtame doesn't
- * imply an edog structure, so we don't want to
- * call tamedog().
- */
- mtmp->mtame = 10;
- /* make him strong enough vs. endgame foes */
- mtmp->m_lev = rn1(8,15);
- mtmp->mhp = mtmp->mhpmax =
- d((int)mtmp->m_lev,10) + 30 + rnd(30);
- bless(otmp);
- otmp->spe = 7;
- mpickobj(mtmp, otmp);
- }
- }
- }
- }
-
- #ifdef MULDGN
- onquest();
- #endif
- assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
-
- #ifdef INSURANCE
- save_currentstate();
- #endif
-
- if(!flags.nopick && OBJ_AT(u.ux, u.uy) &&
- (!is_pool(u.ux,u.uy) || Underwater))
- pickup(1);
- else read_engr_at(u.ux,u.uy);
- }
-
- /* handle something like portal ejection */
- void
- deferred_goto()
- {
- if (!on_level(&u.uz, &u.utolev)) {
- d_level dest;
- int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
-
- assign_level(&dest, &u.utolev);
- goto_level(&dest, !!(typmask&4), !!(typmask&2), !!(typmask&1));
- if (typmask & 0200) { /* remove portal */
- deltrap(t_at(u.ux, u.uy));
- newsym(u.ux, u.uy);
- }
- }
- }
-
- #endif /* OVL2 */
- #ifdef OVL3
-
- void
- revive_corpse(corpse, odds, mark_as_old) /* see remove_cadavers() */
- register struct obj *corpse;
- int odds;
- boolean mark_as_old;
- {
- register struct monst *mtmp;
-
- corpse->oldcorpse = mark_as_old;
-
- /* odds == 0 is a special case meaning 'always revive' */
- if (!odds || !rn2(odds)) {
- if (carried(corpse)) {
- if (corpse == uwep) {
- if ((mtmp = revive(corpse,TRUE)) != 0)
- pline("The %s%s %s writhes out of your grasp!",
- (mtmp->mhp < mtmp->mhpmax) ? "bite-covered ":"",
- mtmp->data->mname, xname(corpse));
- } else if ((mtmp = revive(corpse,TRUE)) != 0)
- You("feel squirming in your backpack!");
- } else {
- if ((mtmp = revive(corpse,FALSE)) && cansee(mtmp->mx,mtmp->my))
- pline("%s rises from the dead!",
- (mtmp->mhp==mtmp->mhpmax) ? Monnam(mtmp)
- : Adjmonnam(mtmp, "bite-covered"));
- }
- }
- }
-
- /*
- * Remove old cadavers from any object chain. Regenerate trolls
- * thanks to KAA. Follows containers (except ice boxes).
- */
- #define TAINT_AGE 50 /* min. limit for tainting. see eat.c */
- #define ODDS_RV1 37 /* 1/37 odds for 50 moves = 75% revive */
- #define ODDS_RV2 2 /* special case 1/2 odds of reviving */
-
- void
- remove_cadavers(chain)
- struct obj **chain;
- {
- register struct obj *obj, *nobj, *pobj = (struct obj *)0;
- register long corpse_age;
- boolean ininv = (*chain == invent);
- boolean onfloor = (*chain == fobj);
-
- for (obj = *chain; obj; obj = nobj) {
- nobj = obj->nobj;
-
- if (obj->otyp == CORPSE) {
- /* corpses laying on ice deteriorate more slowly */
- if (onfloor && obj->age < monstermoves &&
- rn2(3) && is_ice(obj->ox, obj->oy)) obj->age++;
- corpse_age = monstermoves - obj->age;
-
- if (is_rider(&mons[obj->corpsenm]) && corpse_age >= 12) {
- /* these always come back eventually */
- /* riders can't be picked up, so no need to check onfloor */
- revive_corpse(obj, 3, FALSE);
- } else if (mons[obj->corpsenm].mlet == S_TROLL && !obj->oldcorpse
- && !(mons[obj->corpsenm].geno & (G_GENOD | G_EXTINCT))
- && (onfloor || ininv)) {
-
- /* the corpse has 50 moves, the lower limit for tainting,
- * to attempt re-animation. if it is unsuccessful it is
- * marked to prevent further attempts. if we leave the
- * level and return to old corpses that haven't been marked
- * they're given a one-shot chance to re-animate.
- */
- if (corpse_age < TAINT_AGE)
- revive_corpse(obj, ODDS_RV1, FALSE);
- else if (corpse_age == TAINT_AGE)
- revive_corpse(obj, ODDS_RV1, TRUE);
- else revive_corpse(obj, ODDS_RV2, TRUE);
-
- } else if (obj->corpsenm != PM_LIZARD && (250 < corpse_age)) {
- if(ininv)
- useup(obj);
- else if(onfloor)
- delobj(obj);
- else { /* in a container */
- if(pobj) pobj->nobj = nobj;
- else *chain = nobj;
- obfree(obj, (struct obj *) 0);
- obj = 0;
- }
- }
- } else if(obj->cobj && Is_container(obj) && obj->otyp != ICE_BOX)
- remove_cadavers(&obj->cobj);
- /* pobj is only used for containers, which don't allow revive() -dlc */
- if (obj) pobj = obj;
- }
- }
-
- int
- donull() {
- return(1); /* Do nothing, but let other things happen */
- }
-
- #endif /* OVL3 */
- #ifdef OVLB
-
- STATIC_PTR int
- wipeoff() {
- if(u.ucreamed < 4) u.ucreamed = 0;
- else u.ucreamed -= 4;
- if (Blinded < 4) Blinded = 0;
- else Blinded -= 4;
- if (!Blinded) {
- pline("You've got the glop off.");
- u.ucreamed = 0;
- Blinded = 1;
- make_blinded(0L,TRUE);
- return(0);
- } else if (!u.ucreamed) {
- Your("%s feels clean now.", body_part(FACE));
- return(0);
- }
- return(1); /* still busy */
- }
-
- int
- dowipe()
- {
- if(u.ucreamed) {
- static char NEARDATA buf[39];
-
- Sprintf(buf, "wiping off your %s", body_part(FACE));
- set_occupation(wipeoff, buf, 0);
- /* Not totally correct; what if they change back after now
- * but before they're finished wiping?
- */
- return(1);
- }
- Your("%s is already clean.", body_part(FACE));
- return(1);
- }
-
- #endif /* OVLB */
- #ifdef OVL1
-
- /* split obj so that it gets size num */
- /* remainder is put in the object structure delivered by this call */
- struct obj *
- splitobj(obj, num)
- register struct obj *obj;
- register long num;
- {
- register struct obj *otmp;
- /* assert(0 < num && num < obj->quan); */
- otmp = newobj(obj->onamelth);
- *otmp = *obj; /* copies whole structure */
- otmp->o_id = flags.ident++;
- obj->quan = num;
- obj->owt = weight(obj);
- otmp->quan -= num;
- otmp->owt = weight(otmp); /* -= obj->owt ? */
- obj->nobj = obj->nexthere = otmp;
- if (obj->onamelth)
- (void)strncpy(ONAME(otmp), ONAME(obj), (int)obj->onamelth);
- if(obj->unpaid) splitbill(obj,otmp);
- return(otmp);
- }
-
- #endif /* OVL1 */
- #ifdef OVLB
-
- void
- set_wounded_legs(side, timex)
- register long side;
- register int timex;
- {
- if(!Wounded_legs) {
- ATEMP(A_DEX)--;
- flags.botl = 1;
- }
-
- if(!Wounded_legs || (Wounded_legs & TIMEOUT))
- Wounded_legs |= side + timex;
- else
- Wounded_legs |= side;
- }
-
- void
- heal_legs()
- {
- if(Wounded_legs) {
- if (ATEMP(A_DEX) < 0) {
- ATEMP(A_DEX)++;
- flags.botl = 1;
- }
-
- if((Wounded_legs & BOTH_SIDES) == BOTH_SIDES) {
- Your("%s feel somewhat better.",
- makeplural(body_part(LEG)));
- } else {
- Your("%s feels somewhat better.",
- body_part(LEG));
- }
- Wounded_legs = 0;
- }
- }
-
- #endif /* OVLB */
-
- /*do.c*/
-