Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83 (MC840302); site mcvax.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!godot!harvard!seismo!mcvax!play From: play@mcvax.UUCP (funhouse) Newsgroups: net.sources Subject: Hack sources (part 8 of 15) Message-ID: <6250@mcvax.UUCP> Date: Mon, 17-Dec-84 19:35:03 EST Article-I.D.: mcvax.6250 Posted: Mon Dec 17 19:35:03 1984 Date-Received: Wed, 19-Dec-84 02:15:41 EST Organization: CWI, Amsterdam Lines: 1382 # This is part 8 (of 15) of the Hack sources. Send complaints to # mcvax!play . # This is a shell archive. Remove anything before this line, then # unpack it by saving it in a file and typing "sh file". (Files # unpacked will be owned by you and have default permissions.) # # This archive contains: # hack.makemon.c hack.mfndpos.h hack.mhitu.c hack.mkobj.c hack.mon.c echo x - hack.makemon.c cat > "hack.makemon.c" << '//E*O*F hack.makemon.c//' /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ #ifdef MKLEV #include "mklev.h" extern char *fut_geno; #else MKLEV #include "hack.h" extern char fut_geno[]; #endif MKLEV extern char *index(); struct monst zeromonst; /* * called with [x,y] = coordinates; * [0,0] means anyplace * [u.ux,u.uy] means: call mnexto (not in MKLEV) * * In case we make an Orc or killer bee, we make an entire horde (swarm); * note that in this case we return only one of them (the one at [x,y]). */ struct monst * makemon(ptr,x,y) register struct permonst *ptr; { register struct monst *mtmp; register tmp, ct; boolean anything = (!ptr); if(x != 0 || y != 0) if(m_at(x,y)) return((struct monst *) 0); if(ptr){ if(index(fut_geno, ptr->mlet)) return((struct monst *) 0); } else { ct = CMNUM - strlen(fut_geno); if(index(fut_geno, 'm')) ct++; /* make only 1 minotaur */ if(index(fut_geno, '@')) ct++; if(ct <= 0) return(0); /* no more monsters! */ tmp = rn2(ct*dlevel/24 + 7); if(tmp < dlevel - 4) tmp = rn2(ct*dlevel/24 + 12); if(tmp >= ct) tmp = rn1(ct - ct/2, ct/2); for(ct = 0; ct < CMNUM; ct++){ ptr = &mons[ct]; if(index(fut_geno, ptr->mlet)) continue; if(!tmp--) goto gotmon; } panic("makemon?"); } gotmon: mtmp = newmonst(ptr->pxlth); *mtmp = zeromonst; /* clear all entries in structure */ for(ct = 0; ct < ptr->pxlth; ct++) ((char *) &(mtmp->mextra[0]))[ct] = 0; mtmp->nmon = fmon; fmon = mtmp; #ifndef MKLEV mtmp->m_id = flags.ident++; #endif MKLEV mtmp->data = ptr; mtmp->mxlth = ptr->pxlth; if(ptr->mlet == 'D') mtmp->orig_hp = mtmp->mhp = 80; else if(!ptr->mlevel) mtmp->orig_hp = mtmp->mhp = rnd(4); else mtmp->orig_hp = mtmp->mhp = d(ptr->mlevel, 8); mtmp->mx = x; mtmp->my = y; mtmp->mcansee = 1; if(ptr->mlet == 'M') mtmp->mimic = ']'; #ifndef MKLEV if(x == u.ux && y == u.uy) mnexto(mtmp); if(x == 0 && y == 0) rloc(mtmp); #endif MKLEV if(ptr->mlet == 's' || ptr->mlet == 'S') { mtmp->mhide = mtmp->mundetected = 1; #ifdef MKLEV if(mtmp->mx && mtmp->my) mkobj_at(0, mtmp->mx, mtmp->my); #endif MKLEV } if(ptr->mlet == ':') { mtmp->cham = 1; #ifndef MKLEV (void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]); #endif MKLEV } if(ptr->mlet == 'I') mtmp->minvis = 1; if(ptr->mlet == 'L' || ptr->mlet == 'N' #ifdef MKLEV || rn2(5) #endif MKLEV ) mtmp->msleep = 1; #ifndef NOWORM #ifndef MKLEV if(ptr->mlet == 'w' && getwn(mtmp)) initworm(mtmp); #endif MKLEV #endif NOWORM if(anything) if(ptr->mlet == 'O' || ptr->mlet == 'k') { coord enexto(); coord mm; register int cnt = rnd(10); mm.x = x; mm.y = y; while(cnt--) { mm = enexto(mm.x, mm.y); (void) makemon(ptr, mm.x, mm.y); } } return(mtmp); } coord enexto(xx,yy) register xchar xx,yy; { register xchar x,y; coord foo[15], *tfoo; int range; tfoo = foo; range = 1; do { /* full kludge action. */ for(x = xx-range; x <= xx+range; x++) if(goodpos(x, yy-range)) { tfoo->x = x; tfoo++->y = yy-range; if(tfoo == &foo[15]) goto foofull; } for(x = xx-range; x <= xx+range; x++) if(goodpos(x,yy+range)) { tfoo->x = x; tfoo++->y = yy+range; if(tfoo == &foo[15]) goto foofull; } for(y = yy+1-range; y < yy+range; y++) if(goodpos(xx-range,y)) { tfoo->x = xx-range; tfoo++->y = y; if(tfoo == &foo[15]) goto foofull; } for(y = yy+1-range; y < yy+range; y++) if(goodpos(xx+range,y)) { tfoo->x = xx+range; tfoo++->y = y; if(tfoo == &foo[15]) goto foofull; } range++; } while(tfoo == foo); foofull: return( foo[rn2(tfoo-foo)] ); } goodpos(x,y) /* used only in mnexto and rloc */ { return( ! (x < 1 || x > COLNO-2 || y < 1 || y > ROWNO-2 || m_at(x,y) || levl[x][y].typ < DOOR #ifndef MKLEV || (x == u.ux && y == u.uy) || sobj_at(ENORMOUS_ROCK, x, y) #endif MKLEV )); } //E*O*F hack.makemon.c// echo x - hack.mfndpos.h cat > "hack.mfndpos.h" << '//E*O*F hack.mfndpos.h//' /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ #define ALLOW_TRAPS 0777 #define ALLOW_U 01000 #define ALLOW_M 02000 #define ALLOW_TM 04000 #define ALLOW_ALL (ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS) #define ALLOW_SSM 010000 #define ALLOW_ROCK 020000 #define NOTONL 040000 #define NOGARLIC 0100000 //E*O*F hack.mfndpos.h// echo x - hack.mhitu.c cat > "hack.mhitu.c" << '//E*O*F hack.mhitu.c//' #include "hack.h" extern struct monst *makemon(); /* * mhitu: monster hits you * returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise */ mhitu(mtmp) register struct monst *mtmp; { register struct permonst *mdat = mtmp->data; register int tmp, ctmp; nomul(0); if(!index("&DuxynNF",mdat->mlet) && !u.uswallow) tmp = hitu(mtmp,d(mdat->damn,mdat->damd)); else tmp = 0; ctmp = tmp && !mtmp->mcan && (!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50)); switch(mdat->mlet) { case '&': if(!mtmp->cham && !mtmp->mcan && !rn2(15)) { (void) makemon(PM_DEMON,u.ux,u.uy); } else { (void) hitu(mtmp,d(2,6)); (void) hitu(mtmp,d(2,6)); (void) hitu(mtmp,rnd(3)); (void) hitu(mtmp,rnd(3)); (void) hitu(mtmp,rn1(4,2)); } break; case ',': if(u.uswallow) youswld(mtmp,4+u.uac,5,"The trapper"); else if(tmp) justswld(mtmp,"The trapper"); break; case '\'': if(u.uswallow) youswld(mtmp,rnd(6),7,"The lurker above"); else if(tmp) justswld(mtmp,"The lurker above"); break; case 'A': if(ctmp && rn2(2)) { pline("You feel weaker!"); losestr(1); } break; case 'C': (void) hitu(mtmp,rnd(6)); break; case 'c': if(!rn2(5)) { pline("You hear %s's hissing!", monnam(mtmp)); if(ctmp || !rn2(5)) { pline("You get turned to stone!"); done_in_by(mtmp); } } break; case 'D': if(rn2(6) || mtmp->mcan) { (void) hitu(mtmp,d(3,10)); (void) hitu(mtmp,rnd(8)); (void) hitu(mtmp,rnd(8)); break; } kludge("%s breathes fire!","The dragon"); buzz(-1,mtmp->mx,mtmp->my,u.ux-mtmp->mx,u.uy-mtmp->my); break; case 'd': (void) hitu(mtmp,d(2,4)); break; case 'e': (void) hitu(mtmp,d(3,6)); break; case 'F': if(mtmp->mcan) break; kludge("%s explodes!","The freezing sphere"); if(Cold_resistance) pline("You don't seem affected by it."); else { xchar dn; if(17-(u.ulevel/2) > rnd(20)) { pline("You get blasted!"); dn = 6; } else { pline("You duck the blast..."); dn = 3; } losehp_m(d(dn,6), mtmp); } mondead(mtmp); return(1); case 'g': if(ctmp && multi >= 0 && !rn2(6)) { kludge("You are frozen by %ss juices","the cube'"); nomul(-rnd(10)); } break; case 'h': if(ctmp && multi >= 0 && !rn2(5)) { nomul(-rnd(10)); kludge("You are put to sleep by %ss bite!","the homunculus'"); } break; case 'j': tmp = hitu(mtmp,rnd(3)); tmp &= hitu(mtmp,rnd(3)); if(tmp){ (void) hitu(mtmp,rnd(4)); (void) hitu(mtmp,rnd(4)); } break; case 'k': if((hitu(mtmp,rnd(4)) || !rn2(3)) && ctmp){ poisoned("bee's sting",mdat->mname); } break; case 'L': if(tmp) stealgold(mtmp); break; case 'N': if(mtmp->mcan && !Blind) { pline("%s tries to seduce you, but you seem not interested.", Amonnam(mtmp, "plain")); if(rn2(3)) rloc(mtmp); } else if(steal(mtmp)) { rloc(mtmp); mtmp->mflee = 1; } break; case 'n': if(!uwep && !uarm && !uarmh && !uarms && !uarmg) { pline("%s hits! (I hope you don't mind)", Monnam(mtmp)); u.uhp += rnd(7); if(!rn2(7)) u.uhpmax++; if(u.uhp > u.uhpmax) u.uhp = u.uhpmax; flags.botl = 1; if(!rn2(50)) rloc(mtmp); } else { (void) hitu(mtmp,d(2,6)); (void) hitu(mtmp,d(2,6)); } break; case 'o': tmp = hitu(mtmp,rnd(6)); if(hitu(mtmp,rnd(6)) && ctmp && !u.ustuck && rn2(2)) { u.ustuck = mtmp; kludge("%s has grabbed you!","The owlbear"); u.uhp -= d(2,8); } else if(u.ustuck == mtmp) { u.uhp -= d(2,8); pline("You are being crushed."); } break; case 'P': if(u.uswallow) youswld(mtmp,d(2,4),12,"The purple worm"); else if(ctmp && !rn2(4)) justswld(mtmp,"The purple worm"); else (void) hitu(mtmp,d(2,4)); break; case 'Q': (void) hitu(mtmp,rnd(2)); (void) hitu(mtmp,rnd(2)); break; case 'R': if(tmp && uarmh && !uarmh->rustfree && (int) uarmh->spe >= -1) { pline("Your helmet rusts!"); uarmh->spe--; } else if(ctmp && uarm && !uarmh->rustfree && uarm->otyp < STUDDED_LEATHER_ARMOR && (int)uarm->spe >= -1) { pline("Your armor rusts!"); uarm->spe--; } break; case 'S': if(ctmp && !rn2(8)) { poisoned("snake's bite",mdat->mname); } break; case 's': if(tmp && !rn2(8)) { poisoned("scorpion's sting",mdat->mname); } (void) hitu(mtmp,rnd(8)); (void) hitu(mtmp,rnd(8)); break; case 'T': (void) hitu(mtmp,rnd(6)); (void) hitu(mtmp,rnd(6)); break; case 't': if(!rn2(5)) rloc(mtmp); break; case 'u': mtmp->mflee = 1; break; case 'U': (void) hitu(mtmp,d(3,4)); (void) hitu(mtmp,d(3,4)); break; case 'v': if(ctmp && !u.ustuck) u.ustuck = mtmp; break; case 'V': if(tmp) u.uhp -= 4; if(ctmp && !rn2(3)) losexp(); break; case 'W': if(ctmp && !rn2(5)) losexp(); break; #ifndef NOWORM case 'w': if(tmp) wormhit(mtmp); #endif NOWORM break; case 'X': (void) hitu(mtmp,rnd(3)); (void) hitu(mtmp,rnd(3)); (void) hitu(mtmp,rnd(3)); break; case 'x': { register int side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE; pline("%s pricks in your %s leg!", Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left"); Wounded_legs |= side + rnd(5); losehp_m(2, mtmp); break; } case 'y': if(mtmp->mcan) break; mondead(mtmp); if(!Blind) { pline("You are blinded by a blast of light!"); Blind = d(4,12); seeoff(0); } return(1); case 'Y': (void) hitu(mtmp,rnd(6)); break; } if(u.uhp < 1) done_in_by(mtmp); return(0); } //E*O*F hack.mhitu.c// echo x - hack.mkobj.c cat > "hack.mkobj.c" << '//E*O*F hack.mkobj.c//' /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ #ifdef MKLEV #include "mklev.h" #else #include "hack.h" #endif MKLEV #include "hack.onames.h" char mkobjstr[] = "))[[!!!!????%%%%/=**))[[!!!!????%%%%/=**("; struct obj *mkobj(), *mksobj(); mkobj_at(let,x,y) register let,x,y; { register struct obj *otmp = mkobj(let); otmp->ox = x; otmp->oy = y; otmp->nobj = fobj; fobj = otmp; } #ifndef MKLEV mksobj_at(let,otyp,x,y) register let,otyp,x,y; { register struct obj *otmp = mksobj(let, otyp); otmp->ox = x; otmp->oy = y; otmp->nobj = fobj; fobj = otmp; } #endif MKLEV struct obj * mkobj(let) { if(!let) let = mkobjstr[rn2(sizeof(mkobjstr) - 1)]; return(mksobj(let, letter(let) ? CORPSE : probtype(let))); } struct obj zeroobj; struct obj * mksobj(let, otyp) { register struct obj *otmp; otmp = newobj(0); *otmp = zeroobj; #ifdef MKLEV otmp->age = 0; otmp->o_id = 0; #else otmp->age = moves; otmp->o_id = flags.ident++; #endif MKLEV otmp->quan = 1; if(letter(let)){ otmp->olet = FOOD_SYM; otmp->otyp = CORPSE + ((let > 'Z') ? (let-'a'+'Z'-'@'+1) : (let-'@')); otmp->spe = let; otmp->known = 1; otmp->owt = weight(otmp); return(otmp); } otmp->olet = let; otmp->otyp = otyp; otmp->dknown = index("/=!?*", let) ? 0 : 1; switch(let) { case WEAPON_SYM: otmp->quan = (otmp->otyp <= ROCK) ? rn1(6,6) : 1; if(!rn2(11)) otmp->spe = rnd(3); else if(!rn2(10)) { otmp->cursed = 1; otmp->spe = -rnd(3); } break; case FOOD_SYM: case GEM_SYM: otmp->quan = rn2(6) ? 1 : 2; case TOOL_SYM: case CHAIN_SYM: case BALL_SYM: case ROCK_SYM: case POTION_SYM: case SCROLL_SYM: case AMULET_SYM: break; case ARMOR_SYM: if(!rn2(8)) otmp->cursed = 1; if(!rn2(10)) otmp->spe = rnd(3); else if(!rn2(9)) { otmp->spe = -rnd(3); otmp->cursed = 1; } otmp->spe += 10 - objects[otmp->otyp].a_ac; break; case WAND_SYM: if(otmp->otyp == WAN_WISHING) otmp->spe = 3; else otmp->spe = rn1(5, (objects[otmp->otyp].bits & NODIR) ? 11 : 4); break; case RING_SYM: if(objects[otmp->otyp].bits & SPEC) { if(!rn2(3)) { otmp->cursed = 1; otmp->spe = -rnd(2); } else otmp->spe = rnd(2); } else if(otmp->otyp == RIN_TELEPORTATION || otmp->otyp == RIN_AGGRAVATE_MONSTER || otmp->otyp == RIN_HUNGER || !rn2(9)) otmp->cursed = 1; break; default: panic("impossible mkobj"); } otmp->owt = weight(otmp); return(otmp); } letter(c) { return(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z')); } weight(obj) register struct obj *obj; { register int wt = objects[obj->otyp].oc_weight; return(wt ? wt*obj->quan : (obj->quan + 1)/2); } mkgold(num,x,y) register num; { register struct gen *gtmp; register int amount = num ? num : 1 + (rnd(dlevel+2) * rnd(30)); if(gtmp = g_at(x,y,fgold)) gtmp->gflag += amount; else { gtmp = newgen(); gtmp->ngen = fgold; gtmp->gx = x; gtmp->gy = y; gtmp->gflag = amount; fgold = gtmp; #ifdef MKLEV levl[x][y].scrsym = '$'; #endif MKLEV } } //E*O*F hack.mkobj.c// echo x - hack.mon.c cat > "hack.mon.c" << '//E*O*F hack.mon.c//' /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ #include "hack.h" #include "hack.mfndpos.h" #define SIZE(x) (int)(sizeof(x) / sizeof(x[0])) #define NULL (char *) 0 extern struct monst *makemon(); int warnlevel; /* used by movemon and dochugw */ long lastwarntime; int lastwarnlev; char *warnings[] = { "white", "pink", "red", "ruby", "purple", "black" }; movemon() { register struct monst *mtmp; register int fr; warnlevel = 0; while(1) { /* find a monster that we haven't treated yet */ /* note that mtmp or mtmp->nmon might get killed while mtmp moves, so we cannot just walk down the chain (even new monsters might get created!) */ for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->mlstmv < moves) goto next_mon; /* treated all monsters */ break; next_mon: mtmp->mlstmv = moves; if(mtmp->mblinded && !--mtmp->mblinded) mtmp->mcansee = 1; if(mtmp->mimic) continue; if(mtmp->mspeed != MSLOW || !(moves%2)){ /* continue if the monster died fighting */ fr = -1; if(Conflict && cansee(mtmp->mx,mtmp->my) && (fr = fightm(mtmp)) == 2) continue; if(fr<0 && dochugw(mtmp)) continue; } if(mtmp->mspeed == MFAST && dochugw(mtmp)) continue; } warnlevel -= u.ulevel; if(warnlevel >= SIZE(warnings)) warnlevel = SIZE(warnings)-1; if(warnlevel >= 0) if(warnlevel > lastwarnlev || moves > lastwarntime + 5){ register char *rr; switch(Warning & (LEFT_RING | RIGHT_RING)){ case LEFT_RING: rr = "Your left ring glows"; break; case RIGHT_RING: rr = "Your right ring glows"; break; case LEFT_RING | RIGHT_RING: rr = "Both your rings glow"; break; default: rr = "Your fingertips glow"; break; } pline("%s %s!", rr, warnings[warnlevel]); lastwarntime = moves; lastwarnlev = warnlevel; } dmonsfree(); /* remove all dead monsters */ } justswld(mtmp,name) register struct monst *mtmp; char *name; { mtmp->mx = u.ux; mtmp->my = u.uy; u.ustuck = mtmp; pmon(mtmp); kludge("%s swallows you!",name); more(); seeoff(1); u.uswallow = 1; swallowed(); } youswld(mtmp,dam,die,name) register struct monst *mtmp; register dam,die; char *name; { if(mtmp != u.ustuck) return; kludge("%s digests you!",name); u.uhp -= dam; if(u.uswldtim++ == die){ pline("It totally digests you!"); u.uhp = -1; } if(u.uhp < 1) done_in_by(mtmp); } dochugw(mtmp) register struct monst *mtmp; { register x = mtmp->mx; register y = mtmp->my; register d = dochug(mtmp); register dd; if(!d) /* monster still alive */ if(Warning) if(!mtmp->mpeaceful) if((dd = dist(mtmp->mx,mtmp->my)) < dist(x,y)) if(dd < 100) if(!cansee(mtmp->mx, mtmp->my) || (mtmp->minvis && !See_invisible)) if(mtmp->data->mlevel > warnlevel) warnlevel = mtmp->data->mlevel; return(d); } /* returns 1 if monster died moving, 0 otherwise */ dochug(mtmp) register struct monst *mtmp; { register struct permonst *mdat; register tmp; if(mtmp->cham && !rn2(6)) (void) newcham(mtmp, &mons[dlevel+14+rn2(CMNUM-14-dlevel)]); mdat = mtmp->data; if(mdat->mlevel < 0) panic("bad monster %c (%d)",mdat->mlet,mdat->mlevel); if((!(moves%20) || index("ViT",mdat->mlet)) && mtmp->mhporig_hp) mtmp->mhp++; /* regenerate monsters. */ if(mtmp->mfroz) return(0); /* frozen monsters don't do anything. */ if(mtmp->msleep) {/* wake up a monster, or get out of here. */ if(cansee(mtmp->mx,mtmp->my) && !Stealth && (!index("NL",mdat->mlet) || !rn2(50)) && (Aggravate_monster || (!rn2(7) && !mtmp->mimic))) mtmp->msleep = 0; else return(0); } /* not frozen or sleeping: wipe out texts written in the dust */ wipe_engr_at(mtmp->mx, mtmp->my, 1); /* confused monsters get unconfused with small probability */ if(mtmp->mconf && !rn2(50)) mtmp->mconf = 0; /* some monsters teleport */ if(mtmp->mflee && index("tNL", mdat->mlet) && !rn2(40)){ rloc(mtmp); return(0); } if(mdat->mmove < rnd(6)) return(0); if((mtmp->mflee || mtmp->mconf || (index("BIuy", mdat->mlet) && !rn2(4)) || (mdat->mlet == 'L' && !u.ugold && (mtmp->mgold || rn2(2))) || dist(mtmp->mx,mtmp->my) > 2 || (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful ) && (tmp = m_move(mtmp,0)) && mdat->mmove <= 12) return(tmp == 2); if(tmp == 2) return(1); /* monster died moving */ if(!index("Ea", mdat->mlet) && dist(mtmp->mx, mtmp->my) < 3 && !mtmp->mpeaceful && u.uhp > 0 && !sengr_at("Elbereth", u.ux, u.uy) && !sobj_at(SCR_SCARE_MONSTER, u.ux, u.uy)) { if(mhitu(mtmp)) return(1); /* monster died (e.g. 'y' or 'F') */ } /* extra movement for fast monsters */ if(mdat->mmove-12 > rnd(12)) tmp = m_move(mtmp,1); return(tmp == 2); } inrange(mtmp) register struct monst *mtmp; { register schar tx,ty; /* spit fire only when both in a room or both in a corridor */ if(inroom(u.ux,u.uy) != inroom(mtmp->mx,mtmp->my)) return; tx = u.ux - mtmp->mx; ty = u.uy - mtmp->my; if((!tx && abs(ty) < 8) || (!ty && abs(tx) < 8) || (abs(tx) == abs(ty) && abs(tx) < 8)){ /* spit fire in the direction of @ (not nec. hitting) */ buzz(-1,mtmp->mx,mtmp->my,sgn(tx),sgn(ty)); if(u.uhp < 1) done_in_by(mtmp); } } m_move(mtmp,after) register struct monst *mtmp; { register struct monst *mtmp2; register nx,ny,omx,omy,appr,nearer,cnt,i,j; xchar gx,gy,nix,niy,chcnt; schar chi; boolean likegold, likegems, likeobjs; schar mmoved = 0; /* not strictly nec.: chi >= 0 will do */ coord poss[9]; int info[9]; if(mtmp->mtrapped) { i = mintrap(mtmp); if(i == 2) return(2); /* he died */ if(i == 1) return(0); /* still in trap, so didnt move */ } if(mtmp->mhide && o_at(mtmp->mx,mtmp->my) && rn2(10)) return(0); /* do not leave hiding place */ /* my dog gets a special treatment */ if(mtmp->mtame) { return( dog_move(mtmp, after) ); } /* likewise for shopkeeper */ if(mtmp->isshk) { mmoved = shk_move(); goto postmov; } /* and for the guard */ if(mtmp->isgd) { mmoved = gd_move(); goto postmov; } if(mtmp->data->mlet == 't' && !rn2(5)) { if(rn2(2)) mnexto(mtmp); else rloc(mtmp); mmoved = 1; goto postmov; } if(mtmp->data->mlet == 'D' && !mtmp->mcan) inrange(mtmp); if(!Blind && !Confusion && mtmp->data->mlet == 'U' && !mtmp->mcan && cansee(mtmp->mx,mtmp->my) && rn2(5)) { pline("%s's gaze has confused you!", Monnam(mtmp)); if(rn2(5)) mtmp->mcan = 1; Confusion = d(3,4); /* timeout */ } if(!mtmp->mflee && u.uswallow && u.ustuck != mtmp) return(1); appr = 1; if(mtmp->mflee) appr = -1; if(mtmp->mconf || Invis || !mtmp->mcansee || (index("BIy",mtmp->data->mlet) && !rn2(3))) appr = 0; omx = mtmp->mx; omy = mtmp->my; gx = u.ux; gy = u.uy; if(mtmp->data->mlet == 'L' && appr == 1 && mtmp->mgold > u.ugold) appr = -1; #ifdef TRACK /* random criterion for 'smell' should use mtmp->msmell */ if('a' <= mtmp->data->mlet && mtmp->data->mlet <= 'z') { extern coord *gettrack(); register coord *cp; schar mroom; mroom = inroom(omx,omy); if(mroom < 0 || mroom != inroom(u.ux,u.uy)){ cp = gettrack(omx,omy); if(cp){ gx = cp->x; gy = cp->y; } } } #endif TRACK /* look for gold or jewels nearby */ likegold = (index("LOD", mtmp->data->mlet) != NULL); likegems = (index("ODu", mtmp->data->mlet) != NULL); likeobjs = mtmp->mhide; #define SRCHRADIUS 25 { xchar mind = SRCHRADIUS; /* not too far away */ register int dd; if(likegold){ register struct gen *gold; for(gold = fgold; gold; gold = gold->ngen) if((dd = DIST(omx,omy,gold->gx,gold->gy)) < mind){ mind = dd; gx = gold->gx; gy = gold->gy; } } if(likegems || likeobjs){ register struct obj *otmp; for(otmp = fobj; otmp; otmp = otmp->nobj) if(likeobjs || otmp->olet == GEM_SYM) if(mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0) if((dd = DIST(omx,omy,otmp->ox,otmp->oy)) < mind){ mind = dd; gx = otmp->ox; gy = otmp->oy; } } if(mind < SRCHRADIUS && appr == -1) { if(dist(omx,omy) < 10) { gx = u.ux; gy = u.uy; } else appr = 1; } } nix = omx; niy = omy; cnt = mfndpos(mtmp,poss,info, mtmp->data->mlet == 'u' ? NOTONL : index(" VWZ", mtmp->data->mlet) ? NOGARLIC : ALLOW_TRAPS); /* ALLOW_ROCK for some monsters ? */ chcnt = 0; chi = -1; for(i=0; imtrack[j].x && ny == mtmp->mtrack[j].y) if(rn2(4*(cnt-j))) goto nxti; #ifdef STUPID /* some stupid compilers think that this is too complicated */ { int d1 = DIST(nx,ny,gx,gy); int d2 = DIST(nix,niy,gx,gy); nearer = (d1 < d2); } #else nearer = (DIST(nx,ny,gx,gy) < DIST(nix,niy,gx,gy)); #endif STUPID if((appr == 1 && nearer) || (appr == -1 && !nearer) || !mmoved || (!appr && !rn2(++chcnt))){ nix = nx; niy = ny; chi = i; mmoved = 1; } nxti: ; } if(mmoved){ if(info[chi] & ALLOW_M){ mtmp2 = m_at(nix,niy); if(hitmm(mtmp,mtmp2) == 1 && rn2(4) && hitmm(mtmp2,mtmp) == 2) return(2); return(0); } if(info[chi] & ALLOW_U){ (void) hitu(mtmp, d(mtmp->data->damn, mtmp->data->damd)+1); return(0); } mtmp->mx = nix; mtmp->my = niy; for(j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; mtmp->mtrack[0].x = omx; mtmp->mtrack[0].y = omy; #ifndef NOWORM if(mtmp->wormno) worm_move(mtmp); #endif NOWORM } else { if(mtmp->data->mlet == 'u' && rn2(2)){ rloc(mtmp); return(0); } #ifndef NOWORM if(mtmp->wormno) worm_nomove(mtmp); #endif NOWORM } postmov: if(mmoved == 1) { if(mintrap(mtmp) == 2) /* he died */ return(2); if(likegold) mpickgold(mtmp); if(likegems) mpickgems(mtmp); if(mtmp->mhide) mtmp->mundetected = 1; } pmon(mtmp); return(mmoved); } mpickgold(mtmp) register struct monst *mtmp; { register struct gen *gold; while(gold = g_at(mtmp->mx, mtmp->my, fgold)){ mtmp->mgold += gold->gflag; freegold(gold); if(levl[mtmp->mx][mtmp->my].scrsym == '$') newsym(mtmp->mx, mtmp->my); } } mpickgems(mtmp) register struct monst *mtmp; { register struct obj *otmp; for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp->olet == GEM_SYM) if(otmp->ox == mtmp->mx && otmp->oy == mtmp->my) if(mtmp->data->mlet != 'u' || objects[otmp->otyp].g_val != 0){ freeobj(otmp); mpickobj(mtmp, otmp); if(levl[mtmp->mx][mtmp->my].scrsym == GEM_SYM) newsym(mtmp->mx, mtmp->my); /* %% */ return; /* pick only one object */ } } /* return number of acceptable neighbour positions */ mfndpos(mon,poss,info,flag) register struct monst *mon; coord poss[9]; int info[9], flag; { register int x,y,nx,ny,cnt = 0,tmp; register struct monst *mtmp; x = mon->mx; y = mon->my; if(mon->mconf) { flag |= ALLOW_ALL; flag &= ~NOTONL; } for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) if(nx != x || ny != y) if(isok(nx,ny)) if((tmp = levl[nx][ny].typ) >= DOOR) if(!(nx != x && ny != y && (levl[x][y].typ == DOOR || tmp == DOOR))){ info[cnt] = 0; if(nx == u.ux && ny == u.uy){ if(!(flag & ALLOW_U)) continue; info[cnt] = ALLOW_U; } else if(mtmp = m_at(nx,ny)){ if(!(flag & ALLOW_M)) continue; info[cnt] = ALLOW_M; if(mtmp->mtame){ if(!(flag & ALLOW_TM)) continue; info[cnt] |= ALLOW_TM; } } if(sobj_at(CLOVE_OF_GARLIC, nx, ny)) { if(flag & NOGARLIC) continue; info[cnt] |= NOGARLIC; } if(sobj_at(SCR_SCARE_MONSTER, nx, ny) || (!mon->mpeaceful && sengr_at("Elbereth", nx, ny))) { if(!(flag & ALLOW_SSM)) continue; info[cnt] |= ALLOW_SSM; } if(sobj_at(ENORMOUS_ROCK, nx, ny)) { if(!(flag & ALLOW_ROCK)) continue; info[cnt] |= ALLOW_ROCK; } if(!Invis && online(nx,ny)){ if(flag & NOTONL) continue; info[cnt] |= NOTONL; } /* we cannot avoid traps of an unknown kind */ { register struct gen *gtmp = g_at(nx, ny, ftrap); register int tt; if(gtmp) { tt = 1 << (gtmp->gflag & ~SEEN); if(mon->mtrapseen & tt){ if(!(flag & tt)) continue; info[cnt] |= tt; } } } poss[cnt].x = nx; poss[cnt].y = ny; cnt++; } return(cnt); } dist(x,y) int x,y; { return((x-u.ux)*(x-u.ux) + (y-u.uy)*(y-u.uy)); } poisoned(string, pname) register char *string, *pname; { if(Blind) pline("It was poisoned."); else pline("The %s was poisoned!",string); if(Poison_resistance) { pline("The poison doesn't seem to affect you."); return; } switch(rnd(6)) { case 1: u.uhp = -1; break; case 2: case 3: case 4: losestr(rn1(3,3)); break; case 5: case 6: losehp(rn1(10,6), pname); return; } if(u.uhp < 1) killer = pname; } mondead(mtmp) register struct monst *mtmp; { relobj(mtmp,1); unpmon(mtmp); relmon(mtmp); if(u.ustuck == mtmp) { u.ustuck = 0; if(u.uswallow) { u.uswallow = 0; setsee(); docrt(); } } if(mtmp->isshk) shkdead(); if(mtmp->isgd) gddead(); #ifndef NOWORM if(mtmp->wormno) wormdead(mtmp); #endif NOWORM monfree(mtmp); } /* called when monster is moved to larger structure */ replmon(mtmp,mtmp2) register struct monst *mtmp, *mtmp2; { relmon(mtmp); monfree(mtmp); mtmp2->nmon = fmon; fmon = mtmp2; } relmon(mon) register struct monst *mon; { register struct monst *mtmp; if(mon == fmon) fmon = fmon->nmon; else { for(mtmp = fmon; mtmp->nmon != mon; mtmp = mtmp->nmon) ; mtmp->nmon = mon->nmon; } } /* we do not free monsters immediately, in order to have their name available shortly after their demise */ struct monst *fdmon; /* chain of dead monsters, need not to be saved */ monfree(mtmp) register struct monst *mtmp; { mtmp->nmon = fdmon; fdmon = mtmp; } dmonsfree(){ register struct monst *mtmp; while(mtmp = fdmon){ fdmon = mtmp->nmon; free((char *) mtmp); } } killed(mtmp) struct monst *mtmp; { #ifdef lint #define NEW_SCORING #endif lint register int tmp,tmp2,nk,x,y; register struct permonst *mdat = mtmp->data; if(mtmp->cham) mdat = PM_CHAM; if(Blind) pline("You destroy it!"); else { pline("You destroy %s!", mtmp->mtame ? amonnam(mtmp, "poor") : monnam(mtmp)); } if(u.umconf) { if(!Blind) pline("Your hands stop glowing blue."); u.umconf = 0; } /* count killed monsters */ #define MAXMONNO 100 nk = 1; /* in case we cannot find it in mons */ tmp = mdat - mons; /* index in mons array (if not 'd', '@', ...) */ if(tmp >= 0 && tmp < CMNUM+2) { extern char fut_geno[]; u.nr_killed[tmp]++; if((nk = u.nr_killed[tmp]) > MAXMONNO && !index(fut_geno, mdat->mlet)) charcat(fut_geno, mdat->mlet); } /* punish bad behaviour */ if(mdat->mlet == '@') Telepat = 0, u.uluck -= 2; if(mtmp->mpeaceful || mtmp->mtame) u.uluck--; if(mdat->mlet == 'u') u.uluck -= 5; /* give experience points */ tmp = 1 + mdat->mlevel * mdat->mlevel; if(mdat->ac < 3) tmp += 2*(7 - mdat->ac); if(index("AcsSDXaeRTVWU&In:P", mdat->mlet)) tmp += 2*mdat->mlevel; if(index("DeV&P",mdat->mlet)) tmp += (7*mdat->mlevel); if(mdat->mlevel > 6) tmp += 50; #ifdef NEW_SCORING /* ------- recent addition: make nr of points decrease when this is not the first of this kind */ { int ul = u.ulevel; int ml = mdat->mlevel; if(ul < 14) /* points are given based on present and future level */ for(tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++) if(u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4<<(tmp2-1)))/nk >= 10*pow((unsigned)(ul-1))) if(++ul == 14) break; tmp2 = ml - ul -1; tmp = (tmp + ((tmp2 < 0) ? 0 : 4<= 10*pow(u.ulevel-1)){ pline("Welcome to level %d.", ++u.ulevel); tmp = rnd(10); if(tmp < 3) tmp = rnd(10); u.uhpmax += tmp; u.uhp += tmp; flags.botl = 1; } /* dispose of monster and make cadaver */ x = mtmp->mx; y = mtmp->my; mondead(mtmp); tmp = mdat->mlet; if(tmp == 'm') { /* he killed a minotaur, give him a wand of digging */ /* note: the dead minotaur will be on top of it! */ mksobj_at(WAND_SYM, WAN_DIGGING, x, y); /* if(cansee(x,y)) atl(x,y,fobj->olet); */ stackobj(fobj); } else #ifndef NOWORM if(tmp == 'w') { mksobj_at(WEAPON_SYM, WORM_TOOTH, x, y); stackobj(fobj); } else #endif NOWORM if(!letter(tmp) || !rn2(3)) tmp = 0; if(levl[x][y].typ >= DOOR) /* might be mimic in wall */ if(x != u.ux || y != u.uy) /* might be here after swallowed */ if(index("NTVm&",mdat->mlet) || rn2(5)) { mkobj_at(tmp,x,y); if(cansee(x,y)) atl(x,y,fobj->olet); stackobj(fobj); } } kludge(str,arg) register char *str,*arg; { if(Blind) { if(*str == '%') pline(str,"It"); else pline(str,"it"); } else pline(str,arg); } rescham() /* force all chameleons to become normal */ { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->cham) { mtmp->cham = 0; (void) newcham(mtmp,PM_CHAM); } } newcham(mtmp,mdat) /* make a chameleon look like a new monster */ /* returns 1 if the monster actually changed */ register struct monst *mtmp; register struct permonst *mdat; { register mhp, hpn, hpd; if(mdat == mtmp->data) return(0); /* still the same monster */ #ifndef NOWORM if(mtmp->wormno) wormdead(mtmp); /* throw tail away */ #endif NOWORM hpn = mtmp->mhp; hpd = (mtmp->data->mlevel)*8; if(!hpd) hpd = 4; mtmp->data = mdat; mhp = (mdat->mlevel)*8; /* new hp: same fraction of max as before */ mtmp->mhp = 2 + (hpn*mhp)/hpd; hpn = mtmp->orig_hp; mtmp->orig_hp = 2 + (hpn*mhp)/hpd; mtmp->minvis = (mdat->mlet == 'I') ? 1 : 0; #ifndef NOWORM if(mdat->mlet == 'w' && getwn(mtmp)) initworm(mtmp); #endif NOWORM unpmon(mtmp); /* necessary for 'I' and to force pmon */ pmon(mtmp); return(1); } mnexto(mtmp) /* Make monster mtmp next to you (if possible) */ struct monst *mtmp; { extern coord enexto(); coord mm; mm = enexto(u.ux, u.uy); mtmp->mx = mm.x; mtmp->my = mm.y; pmon(mtmp); } rloc(mtmp) struct monst *mtmp; { register tx,ty; register char ch = mtmp->data->mlet; #ifndef NOWORM if(ch == 'w' && mtmp->mx) return; /* do not relocate worms */ #endif NOWORM do { tx = rn1(COLNO-3,2); ty = rn2(ROWNO); } while(!goodpos(tx,ty)); mtmp->mx = tx; mtmp->my = ty; if(u.ustuck == mtmp){ if(u.uswallow) { u.ux = tx; u.uy = ty; docrt(); } else u.ustuck = 0; } pmon(mtmp); } ishuman(mtmp) register struct monst *mtmp; { return(mtmp->data->mlet == '@'); } setmangry(mtmp) register struct monst *mtmp; { if(!mtmp->mpeaceful) return; if(mtmp->mtame) return; mtmp->mpeaceful = 0; if(ishuman(mtmp)) pline("%s gets angry!", Monnam(mtmp)); } //E*O*F hack.mon.c// exit 0