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