/* $NetBSD: hack.do.c,v 1.11 2011/08/06 20:29:37 dholland Exp $ */ /* * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, * Amsterdam * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the Stichting Centrum voor Wiskunde en * Informatica, nor the names of its contributors may be used to endorse or * promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright (c) 1982 Jay Fenlason * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #ifndef lint __RCSID("$NetBSD: hack.do.c,v 1.11 2011/08/06 20:29:37 dholland Exp $"); #endif /* not lint */ /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) and 't' (throw) */ #include #include #include #include "hack.h" #include "extern.h" static int drop(struct obj *); static void dropy(struct obj *); int dodrop(void) { return (drop(getobj("0$#", "drop"))); } static int drop(struct obj *obj) { if (!obj) return (0); if (obj->olet == '$') { /* pseudo object */ long amount = OGOLD(obj); if (amount == 0) pline("You didn't drop any gold pieces."); else { mkgold(amount, u.ux, u.uy); pline("You dropped %ld gold piece%s.", amount, plur(amount)); if (Invisible) newsym(u.ux, u.uy); } free(obj); return (1); } if (obj->owornmask & (W_ARMOR | W_RING)) { pline("You cannot drop something you are wearing."); return (0); } if (obj == uwep) { if (uwep->cursed) { pline("Your weapon is welded to your hand!"); return (0); } setuwep((struct obj *) 0); } pline("You dropped %s.", doname(obj)); dropx(obj); return (1); } /* Called in several places - should not produce texts */ void dropx(struct obj *obj) { freeinv(obj); dropy(obj); } static void dropy(struct obj *obj) { if (obj->otyp == CRYSKNIFE) obj->otyp = WORM_TOOTH; obj->ox = u.ux; obj->oy = u.uy; obj->nobj = fobj; fobj = obj; if (Invisible) newsym(u.ux, u.uy); subfrombill(obj); stackobj(obj); } /* drop several things */ int doddrop(void) { return (ggetobj("drop", drop, 0)); } int dodown(void) { if (u.ux != xdnstair || u.uy != ydnstair) { pline("You can't go down here."); return (0); } if (u.ustuck) { pline("You are being held, and cannot go down."); return (1); } if (Levitation) { pline("You're floating high above the stairs."); return (0); } goto_level(dlevel + 1, TRUE); return (1); } int doup(void) { if (u.ux != xupstair || u.uy != yupstair) { pline("You can't go up here."); return (0); } if (u.ustuck) { pline("You are being held, and cannot go up."); return (1); } if (!Levitation && inv_weight() + 5 > 0) { pline("Your load is too heavy to climb the stairs."); return (1); } goto_level(dlevel - 1, TRUE); return (1); } void goto_level(int newlevel, boolean at_stairs) { int fd; boolean up = (newlevel < dlevel); if (newlevel <= 0) done("escaped");/* in fact < 0 is impossible */ if (newlevel > MAXLEVEL) newlevel = MAXLEVEL; /* strange ... */ if (newlevel == dlevel) return; /* this can happen */ glo(dlevel); fd = creat(lock, FMASK); 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("A mysterious force prevents you from going %s.", up ? "up" : "down"); return; } if (Punished) unplacebc(); u.utrap = 0; /* needed in level_tele */ u.ustuck = 0; /* idem */ keepdogs(); seeoff(1); if (u.uswallow) /* idem */ u.uswldtim = u.uswallow = 0; flags.nscrinh = 1; u.ux = FAR; /* hack */ (void) inshop(); /* probably was a trapdoor */ savelev(fd, dlevel); (void) close(fd); dlevel = newlevel; if (maxdlevel < dlevel) maxdlevel = dlevel; glo(dlevel); if (!level_exists[dlevel]) mklev(); else { if ((fd = open(lock, O_RDONLY)) < 0) { pline("Cannot open %s .", lock); pline("Probably someone removed it."); done("tricked"); } getlev(fd, hackpid, dlevel); (void) close(fd); } if (at_stairs) { if (up) { u.ux = xdnstair; u.uy = ydnstair; if (!u.ux) { /* entering a maze from below? */ u.ux = xupstair; /* this will confuse the * player! */ u.uy = yupstair; } if (Punished && !Levitation) { pline("With great effort you climb the stairs."); placebc(1); } } else { u.ux = xupstair; u.uy = yupstair; if (inv_weight() + 5 > 0 || Punished) { pline("You fall down the stairs."); /* %% */ losehp(rnd(3), "fall"); if (Punished) { if (uwep != uball && rn2(3)) { pline("... and are hit by the iron ball."); losehp(rnd(20), "iron ball"); } placebc(1); } selftouch("Falling, you"); } } { struct monst *mtmp = m_at(u.ux, u.uy); if (mtmp) mnexto(mtmp); } } else { /* trapdoor or level_tele */ do { u.ux = rnd(COLNO - 1); u.uy = rn2(ROWNO); } while (levl[u.ux][u.uy].typ != ROOM || m_at(u.ux, u.uy)); if (Punished) { if (uwep != uball && !up /* %% */ && rn2(5)) { pline("The iron ball falls on your head."); losehp(rnd(25), "iron ball"); } placebc(1); } selftouch("Falling, you"); } (void) inshop(); initrack(); losedogs(); { struct monst *mtmp; if ((mtmp = m_at(u.ux, u.uy)) != NULL) mnexto(mtmp); /* riv05!a3 */ } flags.nscrinh = 0; setsee(); seeobjs(); /* make old cadavers disappear - riv05!a3 */ docrt(); pickup(1); read_engr_at(u.ux, u.uy); } int donull(void) { return (1); /* Do nothing, but let other things happen */ } int dopray(void) { nomovemsg = "You finished your prayer."; nomul(-3); return (1); } int dothrow(void) { struct obj *obj; struct monst *mon; int tmp; obj = getobj("#)", "throw"); /* it is also possible to throw food */ /* (or jewels, or iron balls ... ) */ if (!obj || !getdir(1)) /* ask "in what direction?" */ return (0); if (obj->owornmask & (W_ARMOR | W_RING)) { pline("You can't throw something you are wearing."); return (0); } u_wipe_engr(2); if (obj == uwep) { if (obj->cursed) { pline("Your weapon is welded to your hand."); return (1); } if (obj->quan > 1) setuwep(splitobj(obj, 1)); else setuwep((struct obj *) 0); } else if (obj->quan > 1) (void) splitobj(obj, 1); freeinv(obj); if (u.uswallow) { mon = u.ustuck; bhitpos.x = mon->mx; bhitpos.y = mon->my; } else if (u.dz) { if (u.dz < 0) { pline("%s hits the ceiling, then falls back on top of your head.", Doname(obj)); /* note: obj->quan == 1 */ if (obj->olet == POTION_SYM) potionhit(&youmonst, obj); else { if (uarmh) pline("Fortunately, you are wearing a helmet!"); losehp(uarmh ? 1 : rnd((int) (obj->owt)), "falling object"); dropy(obj); } } else { pline("%s hits the floor.", Doname(obj)); if (obj->otyp == EXPENSIVE_CAMERA) { pline("It is shattered in a thousand pieces!"); obfree(obj, Null(obj)); } else if (obj->otyp == EGG) { pline("\"Splash!\""); obfree(obj, Null(obj)); } else if (obj->olet == POTION_SYM) { pline("The flask breaks, and you smell a peculiar odor ..."); potionbreathe(obj); obfree(obj, Null(obj)); } else { dropy(obj); } } return (1); } else if (obj->otyp == BOOMERANG) { mon = boomhit(u.dx, u.dy); if (mon == &youmonst) { /* the thing was caught */ (void) addinv(obj); return (1); } } else { if (obj->otyp == PICK_AXE && shkcatch(obj)) return (1); mon = bhit(u.dx, u.dy, (obj->otyp == ICE_BOX) ? 1 : (!Punished || obj != uball) ? 8 : !u.ustuck ? 5 : 1, obj->olet, (void (*)(struct monst *, struct obj *)) 0, (int (*)(struct obj *, struct obj *)) 0, obj); } if (mon) { /* awake monster if sleeping */ wakeup(mon); if (obj->olet == WEAPON_SYM) { tmp = -1 + u.ulevel + mon->data->ac + abon(); if (obj->otyp < ROCK) { if (!uwep || uwep->otyp != obj->otyp + (BOW - ARROW)) tmp -= 4; else { tmp += uwep->spe; } } else if (obj->otyp == BOOMERANG) tmp += 4; tmp += obj->spe; if (u.uswallow || tmp >= rnd(20)) { if (hmon(mon, obj, 1) == TRUE) { /* mon still alive */ #ifndef NOWORM cutworm(mon, bhitpos.x, bhitpos.y, obj->otyp); #endif /* NOWORM */ } else mon = 0; /* weapons thrown disappear sometimes */ if (obj->otyp < BOOMERANG && rn2(3)) { /* check bill; free */ obfree(obj, (struct obj *) 0); return (1); } } else miss(objects[obj->otyp].oc_name, mon); } else if (obj->otyp == HEAVY_IRON_BALL) { tmp = -1 + u.ulevel + mon->data->ac + abon(); if (!Punished || obj != uball) tmp += 2; if (u.utrap) tmp -= 2; if (u.uswallow || tmp >= rnd(20)) { if (hmon(mon, obj, 1) == FALSE) mon = 0; /* he died */ } else miss("iron ball", mon); } else if (obj->olet == POTION_SYM && u.ulevel > rn2(15)) { potionhit(mon, obj); return (1); } else { if (cansee(bhitpos.x, bhitpos.y)) pline("You miss %s.", monnam(mon)); else pline("You miss it."); if (obj->olet == FOOD_SYM && mon->data->mlet == 'd') if (tamedog(mon, obj)) return (1); if (obj->olet == GEM_SYM && mon->data->mlet == 'u' && !mon->mtame) { if (obj->dknown && objects[obj->otyp].oc_name_known) { if (objects[obj->otyp].g_val > 0) { u.uluck += 5; goto valuable; } else { pline("%s is not interested in your junk.", Monnam(mon)); } } else { /* value unknown to @ */ u.uluck++; valuable: if (u.uluck > LUCKMAX) /* dan@ut-ngp */ u.uluck = LUCKMAX; pline("%s graciously accepts your gift.", Monnam(mon)); mpickobj(mon, obj); rloc(mon); return (1); } } } } /* the code following might become part of dropy() */ if (obj->otyp == CRYSKNIFE) obj->otyp = WORM_TOOTH; obj->ox = bhitpos.x; obj->oy = bhitpos.y; obj->nobj = fobj; fobj = obj; /* prevent him from throwing articles to the exit and escaping */ /* subfrombill(obj); */ stackobj(obj); if (Punished && obj == uball && (bhitpos.x != u.ux || bhitpos.y != u.uy)) { freeobj(uchain); unpobj(uchain); if (u.utrap) { if (u.utraptype == TT_PIT) pline("The ball pulls you out of the pit!"); else { long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; pline("The ball pulls you out of the bear trap."); pline("Your %s leg is severely damaged.", (side == LEFT_SIDE) ? "left" : "right"); set_wounded_legs(side, 500 + rn2(1000)); losehp(2, "thrown ball"); } u.utrap = 0; } unsee(); uchain->nobj = fobj; fobj = uchain; u.ux = uchain->ox = bhitpos.x - u.dx; u.uy = uchain->oy = bhitpos.y - u.dy; setsee(); (void) inshop(); } if (cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x, bhitpos.y); return (1); } /* split obj so that it gets size num */ /* remainder is put in the object structure delivered by this call */ struct obj * splitobj(struct obj *obj, int num) { struct obj *otmp; otmp = newobj(0); *otmp = *obj; /* copies whole structure */ otmp->o_id = flags.ident++; otmp->onamelth = 0; obj->quan = num; obj->owt = weight(obj); otmp->quan -= num; otmp->owt = weight(otmp); /* -= obj->owt ? */ obj->nobj = otmp; if (obj->unpaid) splitbill(obj, otmp); return (otmp); } void more_experienced(int exp, int rexp) { u.uexp += exp; u.urexp += 4 * exp + rexp; if (exp) flags.botl = 1; if (u.urexp >= ((pl_character[0] == 'W') ? 1000 : 2000)) flags.beginner = 0; } void set_wounded_legs(long side, int timex) { if (!Wounded_legs || (Wounded_legs & TIMEOUT)) Wounded_legs |= side + timex; else Wounded_legs |= side; } void heal_legs(void) { if (Wounded_legs) { if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES) pline("Your legs feel somewhat better."); else pline("Your leg feels somewhat better."); Wounded_legs = 0; } }