billr@saab.CNA.TEK.COM (Bill Randle) (07/24/89)
Submitted-by: Izchak Miller <izchak@linc.cis.upenn.edu>
Posting-number: Volume 7, Issue 68
Archive-name: NetHack3/Part13
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 13 (of 38)."
# Contents: src/alloc.c src/mon.c src/polyself.c
# Wrapped by billr@saab on Sun Jul 23 21:32:56 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/alloc.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/alloc.c'\"
else
echo shar: Extracting \"'src/alloc.c'\" \(853 characters\)
sed "s/^X//" >'src/alloc.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)alloc.c 3.0 88/07/21
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X/* since this file is also used in auxiliary programs, don't include all the
X * function declarations for all of nethack
X */
X#define EXTERN_H
X#include "config.h"
X
X#ifdef LINT
X/*
X a ridiculous definition, suppressing
X "possible pointer alignment problem" for (long *) malloc()
X from lint
X*/
Xlong *
Xalloc(n) unsigned int n; {
Xlong dummy = ftell(stderr);
X if(n) dummy = 0; /* make sure arg is used */
X return(&dummy);
X}
X
X#else
X#ifndef __TURBOC__
Xextern void panic P((char *,...));
X
Xlong *
Xalloc(lth)
Xregister unsigned int lth;
X{
X register genericptr_t ptr;
X
X if(!(ptr = malloc(lth)))
X panic("Cannot get %d bytes", lth);
X return((long *) ptr);
X}
X#endif
X
X
X#endif /* LINT /**/
END_OF_FILE
if test 853 -ne `wc -c <'src/alloc.c'`; then
echo shar: \"'src/alloc.c'\" unpacked with wrong size!
fi
# end of 'src/alloc.c'
fi
if test -f 'src/mon.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/mon.c'\"
else
echo shar: Extracting \"'src/mon.c'\" \(31897 characters\)
sed "s/^X//" >'src/mon.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)mon.c 3.0 88/10/31
X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X#include "mfndpos.h"
X#ifdef NAMED_ITEMS
X# include "artifact.h"
X#endif
X
X#ifdef HARD
Xstatic boolean restrap();
X#endif
X
Xlong lastwarntime;
Xint lastwarnlev;
Xstatic const char *warnings[] = {
X "white", "pink", "red", "ruby", "purple", "black" };
Xstruct monst *fdmon; /* chain of dead monsters, need not to be saved */
X
X/* Creates a monster corpse, a "special" corpse, or nothing if it doesn't
X * leave corpses. Monsters which leave "special" corpses should have
X * G_NOCORPSE set in order to prevent wishing for one, finding tins of one,
X * etc....
X */
Xstatic struct obj *
Xmake_corpse(mtmp)
Xregister struct monst *mtmp;
X{
X register struct permonst *mdat = mtmp->data;
X#ifdef GOLEMS
X int pieces;
X#endif
X struct obj *obj = 0;
X int x = mtmp->mx, y = mtmp->my;
X
X switch(monsndx(mdat)) {
X case PM_KOBOLD_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_KOBOLD_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_KOBOLD;
X break;
X case PM_GNOME_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_GNOME_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_GNOME;
X break;
X case PM_ORC_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_ORC_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_ORC;
X break;
X case PM_ELF_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_ELF_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_ELF;
X break;
X case PM_HUMAN_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_HUMAN_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_HUMAN;
X break;
X case PM_GIANT_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_GIANT_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_GIANT;
X break;
X case PM_ETTIN_MUMMY:
X obj = mksobj_at(MUMMY_WRAPPING, x, y); /* and fall through */
X case PM_ETTIN_ZOMBIE:
X obj = mksobj_at(CORPSE, x, y);
X obj->corpsenm = PM_ETTIN;
X break;
X#ifdef GOLEMS
X case PM_IRON_GOLEM:
X pieces = d(2,6);
X while (pieces--)
X obj = mksobj_at(IRON_CHAIN, x, y);
X break;
X case PM_CLAY_GOLEM:
X obj = mksobj_at(ROCK, x, y);
X obj->quan = rn2(20) + 100;
X obj->owt = weight(obj);
X break;
X case PM_STONE_GOLEM:
X obj = mkstatue(mdat, x, y);
X break;
X case PM_WOOD_GOLEM:
X pieces = d(2,4);
X while(pieces--)
X obj = mksobj_at(QUARTERSTAFF, x, y);
X break;
X case PM_LEATHER_GOLEM:
X pieces = d(2,4);
X while(pieces--)
X obj = mksobj_at(LEATHER_ARMOR, x, y);
X break;
X#endif
X default:
X if (mdat->geno & G_NOCORPSE)
X return (struct obj *)0;
X else obj = mkcorpse_at(mdat, x, y);
X break;
X }
X /* All special cases should precede the G_NOCORPSE check */
X
X /* Note: oname() cannot be used generically for non-inventory objects
X * unless you fix the link from the previous object in the chain.
X * (Here we know it's the first one, so there was no link.)
X */
X if (mtmp->mnamelth) {
X obj = oname(obj, NAME(mtmp), 0);
X fobj = obj;
X }
X stackobj(fobj);
X newsym(x, y);
X return obj;
X}
X
X
Xstatic void
Xdmonsfree(){
Xregister struct monst *mtmp;
X while(mtmp = fdmon){
X fdmon = mtmp->nmon;
X free((genericptr_t) mtmp);
X }
X}
X
Xvoid
Xmovemon()
X{
X register struct monst *mtmp;
X register int fr;
X
X warnlevel = 0;
X
X while(1) {
X /* Find a monster that we have not treated yet.
X * Note that mtmp or mtmp->nmon might get killed
X * while mtmp moves, so we cannot just walk down the
X * chain (even new monsters might get created!)
X */
X /* Do tame monsters first. Necessary so that when the tame
X * monster attacks something, the something gets a chance to
X * attack the tame monster back (which it's permitted to do
X * only if it hasn't made its move yet).
X */
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->mlstmv < moves && mtmp->mtame) goto next_mon;
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if(mtmp->mlstmv < moves && !mtmp->mtame) goto next_mon;
X /* treated all monsters */
X break;
X
X next_mon:
X mtmp->mlstmv = moves;
X
X /* most monsters drown in pools */
X { boolean inpool,infountain,iseel,isgremlin;
X
X inpool = is_pool(mtmp->mx,mtmp->my);
X iseel = mtmp->data->mlet == S_EEL;
X isgremlin = mtmp->data->mlet == S_GREMLIN;
X infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ);
X /* Gremlin multiplying won't go on forever since the hit points
X * keep going down, and when it gets to 1 hit point the clone
X * function will fail.
X */
X if((inpool || infountain) && isgremlin && rn2(3)) {
X struct monst *mtmp2 = clone_mon(mtmp);
X
X if (mtmp2) {
X mtmp2->mhpmax = (mtmp->mhpmax /= 2);
X if(cansee(mtmp->mx,mtmp->my))
X pline("%s multiplies.", Monnam(mtmp));
X }
X#ifdef FOUNTAINS
X if (infountain) dryup();
X#endif
X } else
X if(inpool && !is_flyer(mtmp->data) && !is_swimmer(mtmp->data)) {
X if(cansee(mtmp->mx,mtmp->my))
X pline("%s drowns.", Monnam(mtmp));
X mondead(mtmp);
X continue;
X } else
X /* but eels have a difficult time outside */
X if(iseel && !inpool) {
X if(mtmp->mhp > 1) mtmp->mhp--;
X mtmp->mflee = 1;
X mtmp->mfleetim += 2;
X }
X }
X if(mtmp->mblinded && !--mtmp->mblinded)
X mtmp->mcansee = 1;
X if(mtmp->mfleetim && !--mtmp->mfleetim)
X mtmp->mflee = 0;
X#ifdef HARD
X /* unwatched mimics and piercers may hide again [MRS] */
X if(is_hider(mtmp->data) && restrap(mtmp)) continue;
X#endif
X if(mtmp->mimic) continue;
X if(mtmp->mspeed != MSLOW || !(moves%2)){
X /* continue if the monster died fighting */
X fr = -1;
X/* TODO: Handle the case of the agressor dying? */
X if(Conflict && cansee(mtmp->mx,mtmp->my)
X && !mtmp->iswiz
X && (fr = fightm(mtmp)) == 2)
X continue;
X if(fr<0 && dochugw(mtmp))
X continue;
X }
X if(mtmp->mspeed == MFAST && dochugw(mtmp))
X continue;
X }
X#ifdef NAMED_ITEMS
X if (warnlevel == 100) {
X Your("%s %s!", aobjnam(uwep, "glow"),
X Hallucination ? hcolor() : light_blue);
X warnlevel = 0;
X }
X#endif
X warnlevel -= u.ulevel;
X if(warnlevel >= SIZE(warnings))
X warnlevel = SIZE(warnings)-1;
X if(!Blind && warnlevel >= 0)
X if(warnlevel > lastwarnlev || moves > lastwarntime + 5){
X register char *rr;
X
X switch((int) (Warning & (LEFT_RING | RIGHT_RING))){
X case LEFT_RING:
X rr = "Your left ring glows";
X break;
X case RIGHT_RING:
X rr = "Your right ring glows";
X break;
X case LEFT_RING | RIGHT_RING:
X rr = "Both your rings glow";
X break;
X default:
X { char buf[33];
X Sprintf(buf, "Your %s glow", makeplural(body_part(FINGERTIP)));
X rr = buf;
X }
X break;
X }
X pline("%s %s!", rr, Hallucination ? hcolor() : warnings[warnlevel]);
X lastwarntime = moves;
X lastwarnlev = warnlevel;
X }
X
X dmonsfree(); /* remove all dead monsters */
X}
X
Xvoid
Xmeatgold(mtmp)
X register struct monst *mtmp;
X{
X register struct gold *gold;
X register struct obj *otmp;
X
X /* Eats gold if it is there */
X while(gold = g_at(mtmp->mx, mtmp->my)){
X if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X pline("%s eats some gold!", Monnam(mtmp));
X mtmp->meating = (int)((gold->amount + 500L)/1000L);
X freegold(gold);
X /* Left behind a pile? */
X if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X newsym(mtmp->mx, mtmp->my);
X }
X /* Eats topmost metal object if it is there */
X for (otmp = fobj; otmp; otmp = otmp->nobj)
X if (otmp->ox == mtmp->mx && otmp->oy == mtmp->my &&
X objects[otmp->otyp].oc_material == METAL) {
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s eats %s!", Monnam(mtmp),
X distant_name(otmp,doname));
X else if (flags.soundok && flags.verbose)
X You("hear a crunching sound.");
X mtmp->meating = otmp->owt/2 - 1;
X /* Heal up to the object's weight in hp */
X if (mtmp->mhp < mtmp->mhpmax) {
X mtmp->mhp += objects[otmp->otyp].oc_weight;
X if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
X }
X freeobj(otmp);
X /* Left behind a pile? */
X if(rnd(25) < 3) (void) mksobj_at(ROCK, mtmp->mx, mtmp->my);
X newsym(mtmp->mx, mtmp->my);
X break;
X }
X set_omask(mtmp->mx, mtmp->my);
X}
X
Xvoid
Xmeatobj(mtmp) /* for gelatinous cubes */
X register struct monst *mtmp;
X{
X register struct obj *otmp, *otmp2;
X
X /* Eats organic, glass, or wood objects if there */
X /* Engulfs anything else, metal and rock */
X for (otmp = fobj; otmp; otmp = otmp2) {
X otmp2 = otmp->nobj;
X if (otmp->ox == mtmp->mx && otmp->oy == mtmp->my) {
X if(!objects[otmp->otyp].oc_material <= WOOD) {
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s eats %s!", Monnam(mtmp),
X distant_name(otmp, doname));
X else if (flags.soundok && flags.verbose)
X You("hear a slurping sound.");
X /* Heal up to the object's weight in hp */
X if (mtmp->mhp < mtmp->mhpmax) {
X mtmp->mhp += objects[otmp->otyp].oc_weight;
X if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax;
X }
X delobj(otmp); /* munch */
X } else if (otmp->olet != ROCK_SYM && otmp->olet != BALL_SYM) {
X if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X pline("%s engulfs %s.", Monnam(mtmp),
X distant_name(otmp,doname));
X freeobj(otmp);
X mpickobj(mtmp, otmp); /* slurp */
X }
X }
X /* Engulf & devour is instant, so don't set meating */
X newsym(mtmp->mx, mtmp->my);
X }
X set_omask(mtmp->mx, mtmp->my);
X}
X
Xvoid
Xmpickgold(mtmp)
X register struct monst *mtmp;
X{
X register struct gold *gold;
X
X while(gold = g_at(mtmp->mx, mtmp->my)){
X mtmp->mgold += gold->amount;
X if (cansee(mtmp->mx, mtmp->my) && flags.verbose)
X pline("%s picks up some gold.", Monnam(mtmp));
X freegold(gold);
X if(levl[mtmp->mx][mtmp->my].scrsym == GOLD_SYM)
X newsym(mtmp->mx, mtmp->my);
X }
X set_omask(mtmp->mx, mtmp->my);
X}
X
X/* Now includes giants which pick up enormous rocks. KAA */
Xvoid
Xmpickgems(mtmp)
X register struct monst *mtmp;
X{
X register struct obj *otmp;
X
X for(otmp = fobj; otmp; otmp = otmp->nobj)
X if(throws_rocks(mtmp->data) ? otmp->otyp == BOULDER :
X (otmp->olet == GEM_SYM && otmp->otyp < LAST_GEM+5))
X if(otmp->ox == mtmp->mx && otmp->oy == mtmp->my)
X if(mtmp->data->mlet != S_UNICORN
X || objects[otmp->otyp].g_val != 0){
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s picks up %s.", Monnam(mtmp),
X distant_name(otmp, doname));
X freeobj(otmp);
X mpickobj(mtmp, otmp);
X newsym(mtmp->mx, mtmp->my);
X return; /* pick only one object */
X }
X set_omask(mtmp->mx, mtmp->my);
X}
X
Xint
Xcurr_mon_load(mtmp)
Xregister struct monst *mtmp;
X{
X register int curload = 0;
X register struct obj *obj;
X
X for(obj = mtmp->minvent; obj; obj = obj->nobj) {
X if(obj->otyp != BOULDER || !throws_rocks(mtmp->data))
X curload += weight(obj);
X }
X
X return curload;
X}
X
Xint
Xmax_mon_load(mtmp)
Xregister struct monst *mtmp;
X{
X register int maxload;
X
X /* Base monster carrying capacity is equal to human maximum
X * carrying capacity, or half human maximum if not strong.
X * (for a polymorphed player, the value used would be the
X * non-polymorphed carrying capacity instead of max/half max).
X * This is then modified by the ratio between the monster weights
X * and human weights (weight of a human=45). Limits for corpseless
X * monsters are arbitrary.
X */
X maxload = (mtmp->data->cwt ? mtmp->data->cwt : mtmp->data->mlevel*6)
X * MAX_CARR_CAP / 45;
X if (!strongmonst(mtmp->data)) maxload /= 2;
X
X return maxload;
X}
X
X/* for restricting monsters' object-pickup */
Xboolean
Xcan_carry(mtmp,otmp)
Xstruct monst *mtmp;
Xstruct obj *otmp;
X{
X register int newload = weight(otmp);
X
X if (mtmp->isshk) return(TRUE); /* no limit */
X if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE);
X /* otherwise players might find themselves obligated to violate
X * their alignment if the monster takes something they need
X */
X
X /* special--boulder throwers carry unlimited amounts of boulders */
X if (throws_rocks(mtmp->data) && otmp->otyp == BOULDER)
X return(TRUE);
X
X /* nymphs deal in stolen merchandise, but not boulders or statues */
X if (mtmp->data->mlet == S_NYMPH)
X return !(otmp->olet == ROCK_SYM);
X
X if(curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return(FALSE);
X
X return(TRUE);
X}
X
Xvoid
Xmpickstuff(mtmp, str)
X register struct monst *mtmp;
X register char *str;
X{
X register struct obj *otmp;
X
X/* prevent shopkeepers from leaving the door of their shop */
X if(mtmp->isshk && inhishop(mtmp)) return;
X
X for(otmp = fobj; otmp; otmp = otmp->nobj)
X if(index(str, otmp->olet))
X if(otmp->ox == mtmp->mx && otmp->oy == mtmp->my) {
X if(!can_carry(mtmp,otmp)) return;
X if (cansee(mtmp->mx,mtmp->my) && flags.verbose)
X pline("%s picks up %s.", Monnam(mtmp), doname(otmp));
X freeobj(otmp);
X mpickobj(mtmp, otmp);
X if(index(str, (char) levl[mtmp->mx][mtmp->my].scrsym))
X newsym(mtmp->mx, mtmp->my);
X set_omask(mtmp->mx, mtmp->my);
X return; /* pick only one object */
X }
X}
X
X/* return number of acceptable neighbour positions */
Xint
Xmfndpos(mon, poss, info, flag)
X register struct monst *mon;
X coord *poss; /* coord poss[9] */
X long *info; /* long info[9] */
X long flag;
X{
X register int x,y,nx,ny,cnt = 0,ntyp;
X int nowtyp;
X boolean wantpool,poolok;
X
X x = mon->mx;
X y = mon->my;
X nowtyp = levl[x][y].typ;
X
X wantpool = mon->data->mlet == S_EEL;
X poolok = is_flyer(mon->data) || (is_swimmer(mon->data) && !wantpool);
Xnexttry: /* eels prefer the water, but if there is no water nearby,
X they will crawl over land */
X if(mon->mconf) {
X flag |= ALLOW_ALL;
X flag &= ~NOTONL;
X }
X if(!mon->mcansee)
X flag |= ALLOW_SSM;
X for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) {
X if((nx == x && ny == y) || !isok(nx,ny)) continue;
X if(IS_ROCK(ntyp = levl[nx][ny].typ) && !(flag & ALLOW_WALL) &&
X !((flag & ALLOW_DIG) && may_dig(nx,ny))) continue;
X if(IS_DOOR(ntyp) && !amorphous(mon->data) &&
X ((levl[nx][ny].doormask & D_LOCKED &&
X !is_giant(mon->data) && !mon->isshk) ||
X (levl[nx][ny].doormask & D_CLOSED &&
X (verysmall(mon->data) ||
X (!is_giant(mon->data) && nohands(mon->data))))
X ) && !(flag & (ALLOW_WALL|ALLOW_DIG))) continue;
X if(nx != x && ny != y && (IS_DOOR(nowtyp) || IS_DOOR(ntyp)))
X continue;
X if(is_pool(nx,ny) == wantpool || poolok) {
X /* Displacement also displaces the Elbereth/scare monster,
X * as long as you are visible.
X */
X int dispx = (Displaced && (!Invis || perceives(mon->data)) &&
X (mon->mux==nx)) ? u.ux : nx;
X int dispy = (Displaced && (!Invis || perceives(mon->data)) &&
X (mon->muy==ny)) ? u.uy : ny;
X
X info[cnt] = 0;
X if(sobj_at(SCR_SCARE_MONSTER, dispx, dispy)
X#ifdef ELBERETH
X || sengr_at("Elbereth", dispx, dispy)
X#endif
X ) {
X if(!(flag & ALLOW_SSM)) continue;
X info[cnt] |= ALLOW_SSM;
X }
X if((nx == u.ux && ny == u.uy) ||
X (nx == mon->mux && ny == mon->muy)) {
X if(!(flag & ALLOW_U)) continue;
X info[cnt] |= ALLOW_U;
X } else {
X if(levl[nx][ny].mmask) {
X if(!(flag & ALLOW_M)) continue;
X info[cnt] |= ALLOW_M;
X if((m_at(nx,ny))->mtame) {
X if(!(flag & ALLOW_TM)) continue;
X info[cnt] |= ALLOW_TM;
X }
X }
X#if defined(ALTARS) && defined(THEOLOGY)
X /* Note: ALLOW_SANCT only prevents movement, not */
X /* attack, into a temple. */
X if(!in_temple(x, y) && in_temple(nx, ny) &&
X u_in_sanctuary(in_temple(nx, ny))) {
X if(!(flag & ALLOW_SANCT)) continue;
X info[cnt] |= ALLOW_SANCT;
X }
X#endif
X }
X if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) {
X if(flag & NOGARLIC) continue;
X info[cnt] |= NOGARLIC;
X }
X if(sobj_at(BOULDER, nx, ny)) {
X if(!(flag & ALLOW_ROCK)) continue;
X info[cnt] |= ALLOW_ROCK;
X }
X if((!Invis || perceives(mon->data)) && online(nx,ny)){
X if(flag & NOTONL) continue;
X info[cnt] |= NOTONL;
X }
X /* we cannot avoid traps of an unknown kind */
X { register struct trap *ttmp = t_at(nx, ny);
X register long tt;
X if(ttmp) {
X/* tt = 1L << ttmp->ttyp;*/
X/* why don't we just have code look like what it's supposed to do? then it
X/* might start working for every case. try this instead: -sac */
X tt = (ttmp->ttyp < TRAPNUM && ttmp->ttyp);
X /* below if added by GAN 02/06/87 to avoid
X * traps out of range
X */
X if(!(tt & ALLOW_TRAPS)) {
Ximpossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp);
X continue;
X }
X if(mon->mtrapseen & tt) {
X
X if(!(flag & tt)) continue;
X info[cnt] |= tt;
X }
X }
X }
X poss[cnt].x = nx;
X poss[cnt].y = ny;
X cnt++;
X }
X }
X if(!cnt && wantpool && !is_pool(x,y)) {
X wantpool = FALSE;
X goto nexttry;
X }
X return(cnt);
X}
X
Xint
Xdist(x, y)
Xregister int x,y;
X{
X register int dx = x - u.ux, dy = y - u.uy;
X return dx*dx + dy*dy;
X}
X
Xstatic const char *poiseff[] = {
X
X " feel very weak", "r brain is on fire",
X " can't think straight", "r muscles won't obey you",
X " feel very sick", " break out in hives"
X};
X
Xvoid
Xpoisontell(typ)
X
X int typ;
X{
X pline("You%s.", poiseff[typ]);
X}
X
Xvoid
Xpoisoned(string, typ, pname)
Xregister char *string, *pname;
Xregister int typ;
X{
X register int i, plural;
X boolean thrown_weapon = !strncmp(string, "poison", 6);
X /* admittedly a kludge... */
X
X if(strcmp(string, "blast") && !thrown_weapon) {
X /* 'blast' has already given a 'poison gas' message */
X /* so have "poison arrow", "poison dart", etc... */
X plural = (string[strlen(string) - 1] == 's')? 1 : 0;
X if(Blind)
X pline("%s poisoned.", (plural) ? "They were" : "It was");
X else
X pline("The %s %s poisoned!", string, (plural) ? "were" : "was");
X }
X
X if(Poison_resistance) {
X if(!strcmp(string, "blast")) shieldeff(u.ux, u.uy);
X pline("The poison doesn't seem to affect you.");
X return;
X }
X i = rn2(10 + 20*thrown_weapon);
X if(i == 0 && typ != A_CHA) {
X u.uhp = -1;
X pline("The poison was deadly...");
X } else if(i <= 5) {
X pline("You%s!", poiseff[typ]);
X adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), TRUE);
X } else {
X losehp(thrown_weapon ? rnd(6) : rn1(10,6), pname);
X }
X if(u.uhp < 1) {
X killer = pname;
X done("died");
X }
X}
X
Xstatic void
Xm_detach(mtmp)
Xregister struct monst *mtmp;
X{
X#ifdef WALKIES
X if(mtmp->mleashed) m_unleash(mtmp);
X#endif
X relobj(mtmp,1);
X unpmon(mtmp);
X relmon(mtmp);
X unstuck(mtmp);
X}
X
Xvoid
Xmondead(mtmp)
Xregister struct monst *mtmp;
X{
X m_detach(mtmp);
X#ifdef KOPS
X if(mtmp->data->mlet == S_KOP && allow_kops) {
X /* Dead Kops may come back. */
X switch(rnd(5)) {
X case 1: /* returns near the stairs */
X (void) mkmon_at(mtmp->data->mname,xdnstair,ydnstair);
X break;
X case 2: /* randomly */
X (void) mkmon_at(mtmp->data->mname,0,0);
X break;
X default:
X break;
X }
X }
X#endif
X if(mtmp->isshk) shkdead(mtmp);
X if(mtmp->isgd) gddead();
X#ifdef WORM
X if(mtmp->wormno) wormdead(mtmp);
X#endif
X#ifdef HARD
X if(mtmp->iswiz) wizdead(mtmp);
X#endif
X#ifdef MEDUSA
X if(mtmp->data == &mons[PM_MEDUSA]) u.ukilled_medusa = TRUE;
X#endif
X monfree(mtmp);
X}
X
X/* called when monster is moved to larger structure */
Xvoid
Xreplmon(mtmp, mtmp2)
Xregister struct monst *mtmp, *mtmp2;
X{
X relmon(mtmp);
X monfree(mtmp);
X levl[mtmp2->mx][mtmp2->my].mmask = 1;
X mtmp2->nmon = fmon;
X fmon = mtmp2;
X if(u.ustuck == mtmp) u.ustuck = mtmp2;
X if(mtmp2->isshk) replshk(mtmp,mtmp2);
X if(mtmp2->isgd) replgd(mtmp,mtmp2);
X}
X
Xvoid
Xrelmon(mon)
Xregister struct monst *mon;
X{
X register struct monst *mtmp;
X
X if (fmon == 0) panic ("relmon: no fmon available.");
X
X levl[mon->mx][mon->my].mmask = 0;
X
X if(mon == fmon) fmon = fmon->nmon;
X else {
X for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ;
X if(mtmp) mtmp->nmon = mon->nmon;
X else panic("relmon: mon not in list.");
X }
X}
X
X/* we do not free monsters immediately, in order to have their name
X available shortly after their demise */
Xvoid
Xmonfree(mtmp) register struct monst *mtmp; {
X mtmp->nmon = fdmon;
X fdmon = mtmp;
X levl[mtmp->mx][mtmp->my].mmask = 0;
X}
X
Xvoid
Xunstuck(mtmp)
Xregister struct monst *mtmp;
X{
X if(u.ustuck == mtmp) {
X if(u.uswallow){
X u.ux = mtmp->mx;
X u.uy = mtmp->my;
X u.uswallow = 0;
X setsee();
X docrt();
X }
X u.ustuck = 0;
X }
X}
X
Xvoid
Xkilled(mtmp)
Xregister struct monst *mtmp;
X{
X xkilled(mtmp, 1);
X}
X
Xvoid
Xxkilled(mtmp, dest)
X register struct monst *mtmp;
X/*
X * Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse
X * either; dest=3, message but no corpse
X */
X int dest;
X{
X register int tmp, nk, x, y;
X register struct permonst *mdat = mtmp->data;
X register struct obj *otmp;
X boolean chance;
X
X if (dest & 1) {
X if(!cansee(mtmp->mx,mtmp->my)) You("destroy it!");
X else {
X You("destroy %s!",
X mtmp->mtame ? a_monnam(mtmp, "poor") : mon_nam(mtmp));
X }
X }
X
X /* restore chameleon, lycanthropes to true form at death */
X /* cannot do this in make_corpse() since genociding monsters after
X * MAXMONNO were killed does the wrong type
X */
X if(mtmp->cham) mtmp->data = mdat = &mons[PM_CHAMELEON];
X if(mdat == &mons[PM_JACKALWERE])
X mtmp->data = mdat = &mons[PM_WEREJACKAL];
X if(mdat == &mons[PM_WOLFWERE])
X mtmp->data = mdat = &mons[PM_WEREWOLF];
X if(mdat == &mons[PM_RATWERE])
X mtmp->data = mdat = &mons[PM_WERERAT];
X
X if(u.umconf) {
X if(!Blind) {
X Your("%s stop glowing %s.",
X makeplural(body_part(HAND)),
X Hallucination ? hcolor() : red);
X }
X u.umconf = 0;
X }
X
X /* if we have killed MAXMONNO monsters of a given type, and it
X * can be done, genocide that monster.
X */
X tmp = monsndx(mdat);
X u.nr_killed[tmp]++;
X nk = u.nr_killed[tmp];
X#ifdef TOLKIEN
X if(nk > (tmp==PM_NAZGUL ? 9 : MAXMONNO) &&
X !(mons[tmp].geno & (G_NOGEN | G_GENOD))) {
X#else
X if(nk > MAXMONNO && !(mons[tmp].geno & (G_NOGEN | G_GENOD))) {
X#endif
X#ifdef DEBUG
X pline("Automatically genocided %s.", makeplural(mons[tmp].mname));
X#endif
X mons[tmp].geno |= G_GENOD;
X }
X#ifdef MAIL
X /* If you kill the mail daemon, no more mail delivery. -3. */
X else if(tmp==PM_MAIL_DAEMON) mons[tmp].geno |= G_GENOD;
X#endif
X
X /* punish bad behaviour */
X if(is_human(mdat) && !always_hostile(mdat) &&
X (monsndx(mdat) < PM_ARCHEOLOGIST || monsndx(mdat) > PM_WIZARD) &&
X u.ualigntyp != U_CHAOTIC) {
X HTelepat &= ~INTRINSIC;
X change_luck(-2);
X }
X if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1);
X if ((mdat==&mons[PM_BLACK_UNICORN] && u.ualigntyp == U_CHAOTIC) ||
X (mdat==&mons[PM_GREY_UNICORN] && u.ualigntyp == U_NEUTRAL) ||
X (mdat==&mons[PM_WHITE_UNICORN] && u.ualigntyp == U_LAWFUL))
X change_luck(-5);
X
X /* give experience points */
X tmp = experience(mtmp, nk);
X more_experienced(tmp, 0);
X newexplevel(); /* will decide if you go up */
X
X /* adjust alignment points */
X if(mtmp->mtame)
X adjalign(-15); /* bad!! */
X#if defined(ALTARS) && defined(THEOLOGY)
X else if (mtmp->ispriest && !p_coaligned(mtmp))
X adjalign(2);
X#endif
X else if (mtmp->mpeaceful)
X adjalign(-5);
X /* malign was already adjusted for ualigntyp and randomization */
X adjalign(mtmp->malign);
X
X /* dispose of monster and make cadaver */
X if(stoned) {
X monstone(mtmp);
X return;
X }
X
X x = mtmp->mx; y = mtmp->my;
X
X mondead(mtmp);
X
X if((dest & 2)
X#ifdef REINCARNATION
X || dlevel == rogue_level
X#endif
X ) return;
X
X#ifdef WORM
X if(mdat == &mons[PM_LONG_WORM]) {
X (void) mksobj_at(WORM_TOOTH, x, y);
X stackobj(fobj);
X newsym(x,y);
X }
X#endif
X#ifdef MAIL
X if(mdat == &mons[PM_MAIL_DAEMON]) {
X (void) mksobj_at(SCR_MAIL, x, y);
X stackobj(fobj);
X newsym(x,y);
X }
X#endif
X if(!ACCESSIBLE(levl[x][y].typ) ||
X (IS_DOOR(levl[x][y].typ) &&
X levl[x][y].doormask & (D_CLOSED | D_LOCKED))) {
X /* might be mimic in wall or dead eel*/
X newsym(x,y);
X } else if(x != u.ux || y != u.uy) {
X /* might be here after swallowed */
X if (!rn2(6) && !(mdat->geno & G_NOCORPSE)
X#ifdef KOPS
X && mdat->mlet != S_KOP
X#endif
X ) {
X int typ;
X
X otmp = mkobj_at(RANDOM_SYM, x, y);
X /* Don't create large objects from small monsters */
X typ = otmp->otyp;
X if (!bigmonst(mdat) && typ != FOOD_RATION
X#ifdef WALKIES
X && typ != LEASH
X#endif
X && typ != FIGURINE
X && (otmp->owt > 3 ||
X (typ >= SPEAR && typ <= LANCE) ||
X (typ >= SCIMITAR && typ <= KATANA) ||
X (typ == MORNING_STAR || typ == QUARTERSTAFF) ||
X (typ >= BARDICHE && typ <= VOULGE) ||
X (typ>=PLATE_MAIL && typ<=DRAGON_SCALE_MAIL) ||
X (typ == LARGE_SHIELD))) {
X delobj(otmp);
X } else newsym(x,y);
X }
X /* Whether or not it always makes a corpse is, in theory,
X * different from whether or not the corpse is "special";
X * if we want both, we have to specify it explicitly.
X */
X if (bigmonst(mdat)
X#ifdef GOLEMS
X || is_golem(mdat)
X#endif
X ) chance = 1;
X else chance = !rn2((int)
X (2 + ((mdat->geno & G_FREQ)<2) + verysmall(mdat)));
X if (chance)
X (void) make_corpse(mtmp);
X }
X}
X
X/*VARARGS2*/
Xvoid
Xkludge(str, arg, arg2, arg3)
X register char *str,*arg,*arg2,*arg3;
X{
X if(Blind || !flags.verbose) {
X if(*str == '%') pline(str,"It",arg2,arg3);
X else pline(str,"it",arg2,arg3);
X } else pline(str,arg,arg2,arg3);
X}
X
Xvoid
Xrescham() { /* force all chameleons to become normal */
X
X register struct monst *mtmp;
X
X for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
X if(mtmp->cham) {
X mtmp->cham = 0;
X (void) newcham(mtmp, &mons[PM_CHAMELEON]);
X }
X if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN)
X (void) new_were(mtmp);
X }
X}
X
X/* Let the chameleons change again -dgk */
Xvoid
Xrestartcham() {
X
X register struct monst *mtmp;
X
X for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
X if (mtmp->data->mlet == S_CHAMELEON)
X mtmp->cham = 1;
X}
X
Xint
Xnewcham(mtmp, mdat) /* make a chameleon look like a new monster */
X /* returns 1 if the monster actually changed */
X register struct monst *mtmp;
X register struct permonst *mdat;
X{
X register int mhp, hpn, hpd;
X int tryct;
X
X /* mdat = 0 -> caller wants a random monster shape */
X tryct = 0;
X if(mdat == 0) {
X while (++tryct < 100) {
X static int num;
X mdat = &mons[num=rn2(NUMMONS)];
X if ((!is_human(mdat) || num == PM_NURSE)
X && !type_is_pname(mdat)
X && !is_were(mdat)
X#ifdef MEDUSA
X && num != PM_MEDUSA
X#endif
X#ifdef MAIL
X && num != PM_MAIL_DAEMON
X#endif
X )
X break;
X }
X if (tryct >= 100) return(0); /* Should never happen */
X }
X if(mdat == mtmp->data) return(0); /* still the same monster */
X
X#ifdef WORM
X if(mtmp->wormno) wormdead(mtmp); /* throw tail away */
X#endif
X mtmp->m_lev = adj_lev(mdat); /* new monster level */
X
X hpn = mtmp->mhp;
X hpd = (mtmp->m_lev < 50) ? (mtmp->m_lev)*8 : mdat->mlevel;
X if(!hpd) hpd = 4;
X mhp = (mtmp->m_lev < 50) ? (mtmp->m_lev)*8 : mdat->mlevel;
X if(!mhp) mhp = 4;
X
X /* new hp: same fraction of max as before */
X#ifndef LINT
X mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd);
X#endif
X if(mtmp->mhp < 0) mtmp->mhp = hpn; /* overflow */
X/* Unlikely but not impossible; a 1HD creature with 1HP that changes into a
X 0HD creature will require this statement */
X if (!mtmp->mhp) mtmp->mhp = 1;
X
X/* and the same for maximum hit points */
X hpn = mtmp->mhpmax;
X#ifndef LINT
X mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd);
X#endif
X if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn; /* overflow */
X if (!mtmp->mhpmax) mtmp->mhpmax = 1;
X
X mtmp->data = mdat;
X mtmp->minvis = !!(mdat->mlet == S_STALKER);
X mtmp->mhide = !!hides_under(mdat);
X if (!mtmp->mhide) mtmp->mundetected = 0;
X if (u.ustuck == mtmp
X#ifdef POLYSELF
X && !sticks(uasmon)
X#endif
X && !sticks(mdat))
X u.ustuck = 0;
X#ifdef WORM
X if(mdat == &mons[PM_LONG_WORM] && getwn(mtmp)) initworm(mtmp);
X /* perhaps we should clear mtmp->mtame here? */
X#endif
X unpmon(mtmp); /* necessary for 'I' and to force pmon */
X pmon(mtmp);
X return(1);
X}
X
Xvoid
Xmnexto(mtmp) /* Make monster mtmp next to you (if possible) */
X struct monst *mtmp;
X{
X coord mm;
X enexto(&mm, u.ux, u.uy);
X levl[mtmp->mx][mtmp->my].mmask = 0;
X levl[mm.x][mm.y].mmask = 1;
X mtmp->mx = mm.x;
X mtmp->my = mm.y;
X pmon(mtmp);
X set_apparxy(mtmp);
X}
X
Xvoid
Xmnearto(mtmp,x,y,gz) /* Make monster near (or at) location if possible */
X register struct monst *mtmp;
X xchar x, y;
X boolean gz;
X{
X coord mm;
X if(!gz || !goodpos(x,y)) {
X enexto(&mm, x, y);
X x = mm.x; y = mm.y;
X }
X if(x == mtmp->mx && y == mtmp->my) /* that was easy */
X return;
X levl[mtmp->mx][mtmp->my].mmask = 0;
X levl[x][y].mmask = 1;
X mtmp->mx = x;
X mtmp->my = y;
X pmon(mtmp);
X set_apparxy(mtmp);
X}
X
Xvoid
Xsetmangry(mtmp)
X register struct monst *mtmp;
X{
X if(!mtmp->mpeaceful) return;
X if(mtmp->mtame) return;
X mtmp->mpeaceful = 0;
X#if defined(ALTARS) && defined(THEOLOGY)
X if(mtmp->ispriest) {
X if(p_coaligned(mtmp)) adjalign(-5); /* very bad */
X else adjalign(2);
X } else
X#endif
X adjalign(-1); /* attacking peaceful monsters is bad */
X if(humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd)
X pline("%s gets angry!", Monnam(mtmp));
X#ifdef SOUNDS
X else if (flags.verbose && flags.soundok) growl(mtmp);
X#endif
X}
X
Xint
Xdisturb(mtmp) /* awaken monsters while in the same room.
X * return a 1 if they have been woken.
X */
X register struct monst *mtmp;
X{
X /* wake up, or get out of here. */
X /* ettins are hard to surprise */
X /* Nymphs and Leprechauns do not easily wake up */
X if(cansee(mtmp->mx,mtmp->my) &&
X (!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) &&
X (!(mtmp->data->mlet == S_NYMPH
X || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) &&
X (Aggravate_monster ||
X (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_HUMAN) ||
X (!rn2(7) && !mtmp->mimic))) {
X mtmp->msleep = 0;
X return(1);
X }
X if(Hallucination) pmon(mtmp);
X return(0);
X}
X
X#ifdef HARD
Xstatic boolean
Xrestrap(mtmp)
X/* unwatched hiders may hide again,
X * if so, a 1 is returned.
X */
Xregister struct monst *mtmp;
X{
X if(mtmp->cham || mtmp->mcan || mtmp->mimic ||
X cansee(mtmp->mx, mtmp->my) || rn2(3))
X return(FALSE);
X
X if(mtmp->data->mlet == S_MIMIC) {
X set_mimic_sym(mtmp);
X return(TRUE);
X } else
X if(levl[mtmp->mx][mtmp->my].typ == ROOM) {
X (void) maketrap(mtmp->mx, mtmp->my, MONST_TRAP);
X /* override type selection */
X ftrap->pm = monsndx(mtmp->data);
X mondead(mtmp);
X return(TRUE);
X }
X
X return(FALSE);
X}
X#endif
X
X/* drop (perhaps) a cadaver and remove monster */
Xvoid
Xmondied(mdef)
Xregister struct monst *mdef;
X{
X mondead(mdef);
X if(rn2(3)
X#ifdef REINCARNATION
X && dlevel != rogue_level
X#endif
X )
X (void) make_corpse(mdef);
X}
X
X/* monster disappears, not dies */
Xvoid
Xmongone(mdef)
Xregister struct monst *mdef;
X{
X register struct obj *otmp, *otmp2;
X
X /* release monster's inventory */
X for (otmp = mdef->minvent; otmp; otmp = otmp2) {
X otmp2 = otmp->nobj;
X obfree(otmp, (struct obj *)0);
X }
X mdef->minvent = 0;
X mdef->mgold = 0;
X m_detach(mdef);
X monfree(mdef);
X}
X
X/* drop a statue or rock and remove monster */
Xvoid
Xmonstone(mdef)
Xregister struct monst *mdef;
X{
X struct obj *otmp;
X
X if(!verysmall(mdef->data) ||
X !rn2(2 + ((mdef->data->geno & G_FREQ) > 2))) {
X otmp = mk_named_object(STATUE, mdef->data, mdef->mx, mdef->my,
X NAME(mdef), (int)mdef->mnamelth);
X otmp->spe = 0; /* no book inside */
X } else
X (void) mksobj_at(ROCK, mdef->mx, mdef->my);
X
X stackobj(fobj);
X
X if(cansee(mdef->mx, mdef->my)){
X unpmon(mdef);
X atl(mdef->mx,mdef->my,Hallucination ? rndobjsym() : fobj->olet);
X }
X mondead(mdef);
X}
X
X#ifdef GOLEMS
Xvoid
Xgolemeffects(mon, damtype, dam)
Xregister struct monst *mon;
Xint damtype, dam;
X{
X int heal=0, slow=0;
X
X if (mon->data != &mons[PM_FLESH_GOLEM]
X && mon->data != &mons[PM_IRON_GOLEM])
X return;
X
X if (mon->data == &mons[PM_FLESH_GOLEM]) {
X if (damtype == AD_ELEC) heal = dam / 6;
X else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1;
X } else {
X if (damtype == AD_ELEC) slow = 1;
X else if (damtype == AD_FIRE) heal = dam;
X }
X if (slow) {
X if (mon->mspeed != MSLOW) {
X if (mon->mspeed == MFAST) mon->mspeed = 0;
X else mon->mspeed = MSLOW;
X if (cansee(mon->mx, mon->my))
X pline("%s seems to be moving slower.",
X Monnam(mon));
X }
X }
X if (heal) {
X if (mon->mhp < mon->mhpmax) {
X mon->mhp += dam;
X if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax;
X if (cansee(mon->mx, mon->my))
X pline("%s seems healthier.", Monnam(mon));
X }
X }
X}
X#endif /* GOLEMS */
END_OF_FILE
if test 31897 -ne `wc -c <'src/mon.c'`; then
echo shar: \"'src/mon.c'\" unpacked with wrong size!
fi
# end of 'src/mon.c'
fi
if test -f 'src/polyself.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'src/polyself.c'\"
else
echo shar: Extracting \"'src/polyself.c'\" \(18377 characters\)
sed "s/^X//" >'src/polyself.c' <<'END_OF_FILE'
X/* SCCS Id: @(#)polyself.c 3.0 88/10/22
X/* Polymorph self routine. Copyright (C) 1987, 1988, 1989 by Ken Arromdee */
X/* NetHack may be freely redistributed. See license for details. */
X
X#include "hack.h"
X
X#ifdef POLYSELF
X
Xstatic void break_armor(), drop_weapon();
Xstatic void skinback();
Xstatic void uunstick();
X
Xvoid
Xpolyself()
X{
X char buf[BUFSZ];
X int tmp, tmp2, mntmp = -1;
X int tries=0;
X boolean draconian = (uarm && uarm->otyp==DRAGON_SCALE_MAIL &&
X uarm->corpsenm >= PM_GREY_DRAGON &&
X uarm->corpsenm <= PM_YELLOW_DRAGON);
X /* We have to calculate sticky in multiple places since we might go
X * through any one of them without going through the others.
X */
X boolean sticky = sticks(uasmon) && u.ustuck && !u.uswallow;
X
X if(!Polymorph_control && !draconian) {
X if (rn2(20) > ACURR(A_CON)) {
X You("shudder for a moment.");
X losehp(rn2(30),"system shock");
X return;
X }
X }
X
X if (Polymorph_control) {
X do {
X pline("Become what kind of monster? [type the name] ");
X getlin(buf);
X mntmp = name_to_mon(buf);
X if (mntmp < 0)
X pline("I've never heard of such monsters.");
X else if (!polyok(&mons[mntmp]))
X You("cannot polymorph into that.");
X else break;
X } while(++tries < 5);
X if (tries==5) pline(thats_enough_tries);
X } else if (draconian)
X mntmp = uarm->corpsenm;
X
X if (mntmp < 0) {
X tries = 0;
X do {
X mntmp = rn2(PM_CHAMELEON);
X /* All valid monsters are from 0 to PM_CHAMELEON-1 */
X } while(!polyok(&mons[mntmp]) && tries++ < 200);
X }
X
X if (draconian && mntmp==uarm->corpsenm) {
X if (!(mons[uarm->corpsenm].geno & G_GENOD)) {
X You("merge with your scaly armor.");
X uskin = uarm;
X uarm = (struct obj *)0;
X }
X }
X /* The below polyok() should never fail unless just about everything
X * was genocided...
X */
X if (!polyok(&mons[mntmp]) || !rn2(5)) {
X if (!rn2(10)) {
X flags.female = !flags.female;
X max_rank_sz();
X if (pl_character[0]=='P')
X Strcpy(pl_character+6, flags.female?"ess":"");
X if (pl_character[0]=='C')
X Strcpy(pl_character+5,
X flags.female ? "woman" : "man");
X }
X if (u.umonnum != -1) {
X u.acurr = u.macurr; /* restore old attribs */
X u.amax = u.mamax;
X }
X tmp = u.uhpmax;
X tmp2 = u.ulevel;
X u.usym = S_HUMAN;
X u.umonnum = -1;
X if (u.uundetected) u.uundetected = 0;
X prme();
X u.mtimedone = u.mh = u.mhmax = 0;
X u.ulevel = u.ulevel-2+rn2(5);
X if (u.ulevel > 127 || u.ulevel == 0) u.ulevel = 1;
X if (u.ulevel > MAXULEV) u.ulevel = MAXULEV;
X
X for(tmp = u.ulevel; tmp != tmp2; tmp += (tmp2 < u.ulevel) ? -1 : 1)
X adjabil((tmp2 > u.ulevel) ? -1 : 1);
X tmp = u.uhpmax;
X
X /* random experience points for the new experience level */
X u.uexp = rndexp();
X#ifndef LINT
X u.uhpmax = (u.uhpmax-10)*(long)u.ulevel/tmp2 + 19 - rn2(19);
X#endif
X/* If it was u.uhpmax*u.ulevel/tmp+9-rn2(19), then a 1st level character
X with 16 hp who polymorphed into a 3rd level one would have an average
X of 48 hp. */
X#ifndef LINT
X u.uhp = u.uhp * (long)u.uhpmax/tmp;
X#endif
X#ifdef SPELLS
X tmp = u.uenmax;
X#ifndef LINT
X u.uenmax = u.uenmax * (long)u.ulevel/tmp2 + 9 - rn2(19);
X#endif
X if (u.uenmax < 0) u.uenmax = 0;
X#ifndef LINT
X u.uen = (tmp ? u.uen * (long)u.uenmax / tmp : u.uenmax);
X#endif
X#endif
X (void)redist_attr();
X u.uhunger = rn1(500,500);
X Sick = 0;
X Stoned = 0;
X if (u.uhp <= 0 || u.uhpmax <= 0) {
X
X if(Polymorph_control) {
X if (u.uhp <= 0) u.uhp = 1;
X if (u.uhpmax <= 0) u.uhpmax = 1;
X } else {
X Your("new form doesn't seem healthy enough to survive.");
X killer="unsuccessful polymorph";
X done("died");
X }
X }
X set_uasmon();
X You("feel like a new %sman!", flags.female ? "wo" : "");
X#ifdef WIZARD
X if(!wizard) {
X#endif
Xnewname: more();
X do {
X pline("What is your new name? ");
X getlin(buf);
X } while (buf[0]=='\033' || buf[0]==0);
X if (!strcmp(plname,buf)) {
X pline("That is the same as your old name!");
X goto newname;
X }
X (void)strncpy(plname, buf, sizeof(plname)-1);
X Sprintf(SAVEF, "save/%d%s", getuid(), plname);
X regularize(SAVEF+5); /* avoid . or / in name */
X#ifdef WIZARD
X }
X#endif
X flags.botl = 1;
X skinback();
X find_ac();
X if (sticky) uunstick();
X } else if(!polymon(mntmp)) return;
X
X if (!uarmg) selftouch("No longer petrify-resistant, you");
X if (Inhell && !Fire_resistance) {
X You("burn to a crisp.");
X killer = "unwise polymorph";
X done("burned");
X }
X}
X
Xint
Xpolymon(mntmp) /* returns 1 if polymorph successful */
X int mntmp;
X{
X int tmp;
X boolean sticky = sticks(uasmon) && u.ustuck && !u.uswallow;
X
X if (mons[mntmp].geno & G_GENOD) {
X You("feel rather %s-ish.",mons[mntmp].mname);
X return(0);
X }
X
X if (u.umonnum == -1) {
X /* Human to monster; save human stats */
X u.macurr = u.acurr;
X u.mamax = u.amax;
X } else {
X /* Monster to monster; restore human stats, to be
X * immediately changed to provide stats for the new monster
X */
X u.acurr = u.macurr;
X u.amax = u.mamax;
X }
X u.umonnum = mntmp;
X set_uasmon();
X u.usym = mons[mntmp].mlet;
X /* New stats for monster, to last only as long as polymorphed.
X * Currently only strength gets changed.
X */
X if(strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = 118;
X
X if (resists_ston(uasmon) && Stoned) { /* parnes@eniac.seas.upenn.edu */
X Stoned = 0;
X You("no longer seem to be petrifying.");
X }
X if (u.usym == S_FUNGUS && Sick) {
X Sick = 0;
X You("no longer feel sick.");
X }
X if (u.usym == S_DRAGON && mntmp >= PM_GREY_DRAGON) u.mhmax = 80;
X#ifdef GOLEMS
X else if (is_golem(uasmon)) u.mhmax = golemhp(mntmp);
X#endif /* GOLEMS */
X else {
X
X /*
X tmp = adj_lev(&mons[mntmp]);
X * We can't do this, since there's no such thing as an
X * "experience level of you as a monster" for a polymorphed
X * character.
X */
X tmp = mons[mntmp].mlevel;
X if (!tmp) u.mhmax = rnd(4);
X else u.mhmax = d(tmp, 8);
X }
X u.mh = u.mhmax;
X You("turn into a%s %s!",
X index(vowels, *(mons[mntmp].mname)) ? "n" : "",
X mons[mntmp].mname);
X if (uskin && mntmp != uskin->corpsenm)
X skinback();
X break_armor();
X drop_weapon(1);
X if (u.uundetected && !hides_under(uasmon)) u.uundetected = 0;
X else if (hides_under(uasmon) && (levl[u.ux][u.uy].omask ||
X levl[u.ux][u.uy].gmask))
X u.uundetected = 1;
X prme();
X if (!sticky && !u.uswallow && u.ustuck && sticks(uasmon)) u.ustuck = 0;
X else if (sticky && !sticks(uasmon)) uunstick();
X u.mtimedone = 500 + rn2(500);
X if (u.ulevel < mons[mntmp].mlevel)
X /* Low level characters can't become high level monsters for long */
X u.mtimedone = u.mtimedone * u.ulevel / mons[mntmp].mlevel;
X flags.botl = 1;
X if (can_breathe(uasmon))
X pline("Use the command #monster for breath weapon.");
X if (attacktype(uasmon, AT_SPIT))
X pline("Use the command #monster to spit venom.");
X if (u.usym == S_NYMPH)
X pline("Use the command #monster if you have to remove an iron ball.");
X if (u.usym == S_UMBER)
X pline("Use the command #monster to confuse monsters.");
X if (is_hider(uasmon))
X pline("Use the command #monster to hide.");
X if (is_were(uasmon))
X pline("Use the command #monster to summon help.");
X if (webmaker(uasmon))
X pline("Use the command #monster to spin a web.");
X if (lays_eggs(uasmon) || u.umonnum == PM_QUEEN_BEE)
X pline("Use the command #sit to lay an egg.");
X find_ac();
X return(1);
X}
X
Xstatic void
Xbreak_armor() {
X struct obj *otmp;
X
X if (breakarm(uasmon)) {
X if (otmp = uarm) {
X You("break out of your armor!");
X (void) Armor_gone();
X useup(otmp);
X }
X if (otmp = uarmc) {
X Your("cloak tears apart!");
X (void) Cloak_off();
X useup(otmp);
X }
X#ifdef SHIRT
X if (uarmu) {
X Your("shirt rips to shreds!");
X useup(uarmu);
X }
X#endif
X } else if (sliparm(uasmon)) {
X if (otmp = uarm) {
X Your("armor falls around you!");
X (void) Armor_gone();
X dropx(otmp);
X }
X if (otmp = uarmc) {
X You("shrink out of your cloak!");
X (void) Cloak_off();
X dropx(otmp);
X }
X#ifdef SHIRT
X if (otmp = uarmu) {
X You("become much too small for your shirt!");
X setworn((struct obj *)0, otmp->owornmask & W_ARMU);
X dropx(otmp);
X }
X#endif
X }
X if (nohands(uasmon) || verysmall(uasmon)) {
X if (otmp = uarmg) {
X /* Drop weapon along with gloves */
X You("drop your gloves%s!", uwep ? " and weapon" : "");
X (void) Gloves_off();
X dropx(otmp);
X drop_weapon(0);
X }
X if (otmp = uarms) {
X You("can no longer hold your shield!");
X (void) Shield_off();
X dropx(otmp);
X }
X if (otmp = uarmh) {
X Your("helmet falls to the floor!");
X (void) Helmet_off();
X dropx(otmp);
X }
X if (otmp = uarmf) {
X Your("boots %s off your feet!",
X verysmall(uasmon) ? "slide" : "get pushed");
X (void) Boots_off();
X dropx(otmp);
X }
X }
X}
X
Xstatic void
Xdrop_weapon(alone)
Xint alone;
X{
X struct obj *otmp;
X if (otmp = uwep) {
X /* !alone check below is currently superfluous but in the
X * future it might not be so if there are monsters which cannot
X * wear gloves but can wield weapons
X */
X if (!alone || cantwield(uasmon)) {
X if (alone) You("find you must drop your weapon!");
X uwepgone();
X dropx(otmp);
X }
X }
X}
X
Xvoid
Xrehumanize()
X{
X boolean sticky = sticks(uasmon) && u.ustuck && !u.uswallow;
X
X u.mh = u.mhmax = u.mtimedone = 0;
X u.acurr = u.macurr; /* restore old strength */
X u.amax = u.mamax;
X u.usym = S_HUMAN;
X u.umonnum = -1;
X skinback();
X set_uasmon();
X You("return to %sn form!",(pl_character[0]=='E')?"elve":"huma");
X
X if (u.uhp < 1) done("died");
X if (!Fire_resistance && Inhell) {
X You("burn to a crisp.");
X killer = "dissipating polymorph spell";
X done("burned");
X }
X if (!uarmg) selftouch("No longer petrify-resistant, you");
X if (sticky) uunstick();
X nomul(0);
X if (u.uundetected) u.uundetected = 0;
X prme();
X flags.botl = 1;
X find_ac();
X}
X
Xint
Xdobreathe() {
X if(!getdir(1)) return(0);
X if (rn2(4))
X You("produce a loud and noxious belch.");
X else {
X register struct attack *mattk;
X register int i;
X
X for(i = 0; i < NATTK; i++) {
X mattk = &(uasmon->mattk[i]);
X if(mattk->aatyp == AT_BREA) break;
X }
X buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn,
X u.ux, u.uy, u.dx, u.dy);
X }
X return(1);
X}
X
Xint
Xdospit() {
X struct obj *otmp;
X
X if (!getdir(1)) return(0);
X otmp = mksobj(u.umonnum==PM_COBRA ? BLINDING_VENOM : ACID_VENOM, FALSE);
X (void) throwit(otmp);
X return(1);
X}
X
Xint
Xdoremove() {
X if (!Punished) {
X You("are not chained to anything!");
X return(0);
X }
X unpunish();
X return(1);
X}
X
Xint
Xdospinweb() {
X register struct trap *ttmp = t_at(u.ux,u.uy);
X
X if (Levitation) {
X You("must be on the ground to spin a web.");
X return(0);
X }
X if (u.uswallow) {
X You("release web fluid inside %s.", mon_nam(u.ustuck));
X pline("%s regurgitates you!", Monnam(u.ustuck));
X u.ux = u.ustuck->mx;
X u.uy = u.ustuck->my;
X mnexto(u.ustuck);
X u.uswallow = 0;
X u.ustuck = 0;
X setsee();
X docrt();
X return(1);
X }
X if (u.utrap) {
X You("cannot spin webs while stuck in a trap.");
X return(0);
X }
X if (ttmp) switch (ttmp->ttyp) {
X case SPIKED_PIT:
X case PIT: You("spin a web, covering up the pit.");
X deltrap(ttmp);
X if (Invisible) newsym(u.ux, u.uy);
X return(1);
X case WEB: You("make the web thicker.");
X return(1);
X case SQBRD: pline("The squeaky board is muffled.");
X deltrap(ttmp);
X if (Invisible) newsym(u.ux, u.uy);
X return(1);
X case TELEP_TRAP:
X case LEVEL_TELEP:
X Your("webbing vanishes!");
X return(0);
X case TRAPDOOR: if (!is_maze_lev) {
X You("web over the trapdoor.");
X deltrap(ttmp);
X if (Invisible) newsym(u.ux, u.uy);
X return 1;
X }
X /* Fall through */
X case MGTRP:
X case POLY_TRAP:
X case DART_TRAP:
X case ARROW_TRAP:
X#ifdef SPELLS
X case ANTI_MAGIC:
X#endif
X case LANDMINE:
X case SLP_GAS_TRAP:
X case BEAR_TRAP:
X case RUST_TRAP:
X You("have triggered a trap!");
X dotrap(ttmp);
X return(1);
X default:
X impossible("Webbing over trap type %d?",ttmp->ttyp);
X return(0);
X }
X ttmp = maketrap(u.ux, u.uy, WEB);
X ttmp->tseen = 1;
X if (Invisible) newsym(u.ux, u.uy);
X return(1);
X}
X
Xint
Xdosummon()
X{
X You("call upon your brethren for help!");
X if (!were_summon(uasmon,TRUE))
X pline("But none arrive.");
X return(1);
X}
X
Xint
Xdoconfuse()
X{
X register struct monst *mtmp;
X int looked = 0;
X
X if (Blind) {
X You("can't see anything to gaze at.");
X return 0;
X }
X for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
X if (canseemon(mtmp)) {
X looked = 1;
X if (Invis && !perceives(mtmp->data))
X pline("%s seems not to notice your gaze.", Monnam(mtmp));
X else if (mtmp->minvis && !See_invisible)
X You("can't see where to gaze at %s.", Monnam(mtmp));
X else if (mtmp->mimic)
X continue;
X else if (flags.safe_dog && !Confusion && !Hallucination
X && (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_FELINE)
X && mtmp->mtame) {
X if (mtmp->mnamelth)
X You("avoid gazing at %s.", NAME(mtmp));
X else
X You("avoid gazing at your %s.",
X mtmp->data->mname);
X } else {
X if (flags.confirm && mtmp->mpeaceful && !Confusion
X && !Hallucination) {
X pline("Really confuse %s? ", mon_nam(mtmp));
X (void) fflush(stdout);
X if (yn() != 'y') continue;
X setmangry(mtmp);
X }
X if (mtmp->mfroz || mtmp->mstun || mtmp->msleep ||
X mtmp->mblinded)
X continue;
X if (!mtmp->mconf)
X Your("gaze confuses %s!", mon_nam(mtmp));
X else
X pline("%s is getting more and more confused.",
X Monnam(mtmp));
X mtmp->mconf = 1;
X if ((mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) {
X You("are frozen by %s's gaze!", mon_nam(mtmp));
X nomul((u.ulevel > 6 || rn2(4)) ?
X -d((int)mtmp->m_lev+1,
X (int)mtmp->data->mattk[0].damd)
X : -200);
X return 1;
X }
X#ifdef MEDUSA
X if ((mtmp->data==&mons[PM_MEDUSA]) && !mtmp->mcan) {
X pline("Gazing at an awake medusa is not a very good idea...");
X You("turn to stone...");
X done("stoned");
X }
X#endif
X }
X }
X }
X if (!looked) You("gaze at no place in particular.");
X return 1;
X}
X
Xint
Xdohide()
X{
X if (u.uundetected || u.usym == S_MIMIC_DEF) {
X pline("You are already hiding.");
X return(0);
X }
X if (u.usym == S_MIMIC) {
X u.usym = S_MIMIC_DEF;
X prme();
X } else {
X newsym(u.ux,u.uy);
X u.uundetected = 1;
X }
X return(1);
X}
X
Xstatic void
Xuunstick()
X{
X kludge("%s is no longer in your clutches...", Monnam(u.ustuck));
X u.ustuck = 0;
X}
X
Xstatic void
Xskinback()
X{
X if (uskin) {
X Your("skin returns to its original form.");
X uarm = uskin;
X uskin = (struct obj *)0;
X }
X}
X#endif
X
Xchar *
Xbody_part(part)
X{
X /* Note: it is assumed these will never be >22 characters long,
X * plus the trailing null, after pluralizing (since sometimes a
X * buffer is made a fixed size and must be able to hold it)
X */
X static const char *humanoid_parts[] = { "arm", "eye", "face", "finger",
X "fingertip", "foot", "hand", "handed", "head", "leg",
X "light headed", "neck", "toe" };
X#ifdef POLYSELF
X static const char *jelly_parts[] = { "pseudopod", "dark spot", "front",
X "pseudopod extension", "pseudopod extremity",
X "pseudopod root", "grasp", "grasped", "cerebral area",
X "lower pseudopod", "viscous", "middle",
X "pseudopod extremity" },
X *animal_parts[] = { "forelimb", "eye", "face", "foreclaw", "claw tip",
X "rear claw", "foreclaw", "clawed", "head", "rear limb",
X "light headed", "neck", "rear claw tip" },
X *horse_parts[] = { "forelimb", "eye", "face", "forehoof", "hoof tip",
X "rear hoof", "foreclaw", "hooved", "head", "rear limb",
X "light headed", "neck", "rear hoof tip" },
X *sphere_parts[] = { "appendage", "optic nerve", "body", "tentacle",
X "tentacle tip", "lower appendage", "tentacle", "tentacled",
X "body", "lower tentacle", "rotational", "equator",
X "lower tentacle tip" },
X *fungus_parts[] = { "mycelium", "visual area", "front", "hypha",
X "hypha", "root", "strand", "stranded", "cap area",
X "rhizome", "sporulated", "stalk", "rhizome tip" },
X *vortex_parts[] = { "region", "eye", "front", "minor current",
X "minor current", "lower current", "swirl", "swirled",
X "central core", "lower current", "addled", "center",
X "edge" },
X *snake_parts[] = { "vestigal limb", "eye", "face", "large scale",
X "large scale tip", "rear region", "scale gap", "scale gapped",
X "head", "rear region", "light headed", "neck", "rear scale" };
X
X if (humanoid(uasmon) || (u.usym==S_CENTAUR &&
X (part==ARM || part==FINGER || part==FINGERTIP
X || part==HAND || part==HANDED))) return humanoid_parts[part];
X if (u.usym==S_CENTAUR || u.usym==S_UNICORN) return horse_parts[part];
X if (u.usym==S_SNAKE || u.usym==S_NAGA || u.usym==S_WORM)
X return snake_parts[part];
X if (u.usym==S_EYE) return sphere_parts[part];
X if (u.usym==S_JELLY || u.usym==S_PUDDING) return jelly_parts[part];
X if (u.usym==S_VORTEX || u.usym==S_ELEMENTAL) return vortex_parts[part];
X if (u.usym==S_FUNGUS) return fungus_parts[part];
X return animal_parts[part];
X#else
X return humanoid_parts[part];
X#endif
X}
X
Xint
Xpoly_gender()
X{
X/* Returns gender of polymorphed player; 0/1=same meaning as flags.female,
X * 2=none.
X * Used in:
X * - Seduction by succubus/incubus
X * - Talking to nymphs (sounds.c)
X * Not used in:
X * - Messages given by nymphs stealing armor (they can't steal from
X * incubi/succubi/nymphs, and nonhumanoids can't wear armor).
X * - Amulet of change (must refer to real gender no matter what
X * polymorphed into).
X * - Priest/Priestess, Caveman/Cavewoman (ditto)
X * - Polymorph self (only happens when human)
X * - Shopkeeper messages (since referred to as "creature" and not "sir"
X * or "lady" when polymorphed)
X */
X#ifdef POLYSELF
X if (uasmon->mflags1 & M1_FEM) return 1;
X#ifdef HARD
X if (u.umonnum==PM_INCUBUS) return 0;
X#endif
X if (!humanoid(uasmon)) return 2;
X#endif
X return flags.female;
X}
X
X#ifdef POLYSELF
X#ifdef GOLEMS
Xvoid
Xugolemeffects(damtype, dam)
Xint damtype;
X{
X int heal = 0;
X /* We won't bother with "slow"/"haste" since players do not
X * have a monster-specific slow/haste so there is no way to
X * restore the old velocity once they are back to human.
X */
X if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM)
X return;
X switch (damtype) {
X case AD_ELEC: if (u.umonnum == PM_IRON_GOLEM)
X heal = dam / 6; /* Approx 1 per die */
X break;
X case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM)
X heal = dam;
X break;
X }
X if (heal && (u.mh < u.mhmax)) {
X u.mh += heal;
X if (u.mh > u.mhmax) u.mh = u.mhmax;
X flags.botl = 1;
X pline("Strangely, you feel better than before.");
X }
X}
X#endif /* GOLEMS */
X#endif
END_OF_FILE
if test 18377 -ne `wc -c <'src/polyself.c'`; then
echo shar: \"'src/polyself.c'\" unpacked with wrong size!
fi
# end of 'src/polyself.c'
fi
echo shar: End of archive 13 \(of 38\).
cp /dev/null ark13isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 38 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0