This is mthrowu.c in view mode; [Download] [Up]
/* SCCS Id: @(#)mthrowu.c 3.0 89/11/22 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" OSTATIC int FDECL(movedist,(int,int,int,int)); static void FDECL(drop_throw,(struct obj *,BOOLEAN_P,int,int)); OSTATIC void FDECL(m_throw,(int,int,int,int,int,struct obj *)); #define URETREATING(x,y) (movedist(u.ux,u.uy,x,y) > movedist(u.ux0,u.uy0,x,y)) boolean FDECL(lined_up, (struct monst *)); #ifndef OVLB OSTATIC const char *breathwep[]; #else /* OVLB */ schar tbx = 0, tby = 0; /* used for direction of throw, buzz, etc. */ XSTATIC const char *breathwep[] = { "fragments", "fire", "sleep gas", "frost", "death", "lightning", "poison gas", "acid" }; int thitu(tlev, dam, obj, name) /* u is hit by sth, but not a monster */ register int tlev, dam; struct obj *obj; register const char *name; { const char *onm = an(name); boolean is_acid = (obj && obj->otyp == ACID_VENOM); if(u.uac + tlev <= rnd(20)) { if(Blind || !flags.verbose) pline("It misses."); else You("are almost hit by %s!", onm); return(0); } else { if(Blind || !flags.verbose) You("are hit!"); else You("are hit by %s!", onm); #ifdef POLYSELF if (obj && obj->otyp == SILVER_ARROW && (u.ulycn != -1 || is_demon(uasmon) || u.usym == S_VAMPIRE || (u.usym == S_IMP && u.umonnum != PM_TENGU))) { dam += rnd(20); pline("The %sarrow sears your flesh!", Blind ? "" : "silver "); } if (is_acid && resists_acid(uasmon)) pline("It doesn't seem to hurt you."); else { #endif if (is_acid) pline("It burns!"); losehp(dam, name, KILLED_BY_AN); #ifdef POLYSELF } #endif return(1); } } /* Be sure this corresponds with what happens to player-thrown objects in * dothrow.c (for consistency). --KAA */ static void drop_throw(obj, ohit, x, y) register struct obj *obj; boolean ohit; int x,y; { int create; if (obj->otyp == CREAM_PIE || obj->olet == VENOM_SYM) create = 0; else if (ohit && ((obj->otyp >= ARROW && obj->otyp <= SHURIKEN) || obj->otyp == ROCK)) create = !rn2(3); else create = 1; if (create && !flooreffects(obj,x,y)) { place_object(obj, x, y); obj->nobj = fobj; fobj = obj; stackobj(fobj); } else free((genericptr_t)obj); } XSTATIC void m_throw(x, y, dx, dy, range, obj) register int x,y,dx,dy,range; /* direction and range */ register struct obj *obj; { register struct monst *mtmp; struct obj *singleobj; char sym = obj->olet; int damage; int hitu, blindinc=0; bhitpos.x = x; bhitpos.y = y; singleobj = splitobj(obj, (int)obj->quan-1); /* splitobj leaves the new object in the chain (i.e. the monster's * inventory). Remove it. We can do this in 1 line, but it's highly * dependent on the fact that we know splitobj() places it immediately * after obj. */ obj->nobj = singleobj->nobj; if(sym) { tmp_at(-1, sym); /* open call */ #ifdef TEXTCOLOR tmp_at(-3, (int)objects[obj->otyp].oc_color); #else tmp_at(-3, (int)AT_OBJ); #endif } while(range-- > 0) { /* Actually the loop is always exited by break */ boolean vis; bhitpos.x += dx; bhitpos.y += dy; vis = cansee(bhitpos.x, bhitpos.y); if(MON_AT(bhitpos.x, bhitpos.y)) { mtmp = m_at(bhitpos.x,bhitpos.y); if(mtmp->data->ac + 8 + obj->spe <= rnd(20)) { if (!vis) pline("It is missed."); else miss(distant_name(singleobj,xname), mtmp); if (!range) { /* Last position; object drops */ drop_throw(singleobj, 0, mtmp->mx, mtmp->my); break; } } else { damage = dmgval(obj, mtmp->data); if (damage < 1) damage = 1; if (obj->otyp==ACID_VENOM && resists_acid(mtmp->data)) damage = 0; if (!vis) pline("It is hit%s", exclam(damage)); else hit(distant_name(singleobj,xname), mtmp,exclam(damage)); if (obj->opoisoned) { if (resists_poison(mtmp->data)) { if (vis) pline("The poison doesn't seem to affect %s.", mon_nam(mtmp)); } else { if (rn2(30)) damage += rnd(6); else { if (vis) pline("The poison was deadly..."); damage = mtmp->mhp; } } } if (obj->otyp==SILVER_ARROW && (is_were(mtmp->data) || is_demon(mtmp->data) || mtmp->data->mlet == S_VAMPIRE || (mtmp->data->mlet==S_IMP && mtmp->data != &mons[PM_TENGU]))) { if (vis) pline("The silver arrow sears %s's flesh!", mon_nam(mtmp)); else pline("Its flesh is seared!"); damage += rnd(20); } if (obj->otyp==ACID_VENOM && cansee(mtmp->mx,mtmp->my)){ if (resists_acid(mtmp->data)) { pline("%s is unaffected.", vis ? Monnam(mtmp) : "It"); damage = 0; } else if (vis) pline("The acid burns %s!", mon_nam(mtmp)); else pline("It is burned!"); } mtmp->mhp -= damage; if(mtmp->mhp < 1) { pline("%s is %s!", vis ? Monnam(mtmp) : "It", (is_demon(mtmp->data) || is_undead(mtmp->data) || !vis) ? "destroyed" : "killed"); mondied(mtmp); } if((obj->otyp == CREAM_PIE) || (obj->otyp == BLINDING_VENOM)) { if (vis) pline("%s is blinded by the %s.", Monnam(mtmp), xname(singleobj)); if(mtmp->msleep) mtmp->msleep = 0; mtmp->mcansee = 0; { register unsigned rnd_tmp = rnd(25) + 20; if((mtmp->mblinded + rnd_tmp) > 127) mtmp->mblinded = 127; else mtmp->mblinded += rnd_tmp; } } drop_throw(singleobj, 1, bhitpos.x, bhitpos.y); break; } } if (bhitpos.x == u.ux && bhitpos.y == u.uy) { if (multi) nomul(0); switch(obj->otyp) { int dam; case CREAM_PIE: case BLINDING_VENOM: hitu = thitu(8, 0, singleobj, xname(singleobj)); break; default: dam = dmgval(obj, uasmon); if (dam < 1) dam = 1; hitu = thitu(8+obj->spe, dam, singleobj, xname(singleobj)); } if (hitu && obj->opoisoned) /* it's safe to call xname twice because it's the same object both times... */ poisoned(xname(singleobj), A_STR, xname(singleobj), 10); if(hitu && (obj->otyp == CREAM_PIE || obj->otyp == BLINDING_VENOM)) { blindinc = rnd(25); if(obj->otyp == CREAM_PIE) { if(!Blind) pline("Yecch! You've been creamed."); else pline("There's something sticky all over your %s.", body_part(FACE)); } else { /* venom in the eyes */ if(Blindfolded) /* nothing */ ; else if(!Blind) pline("The venom blinds you."); else Your("%s sting.", makeplural(body_part(EYE))); } } stop_occupation(); if (hitu || !range) { drop_throw(singleobj, hitu, u.ux, u.uy); break; } } else if (!range /* reached end of path */ /* missile hits edge of screen */ || !isok(bhitpos.x+dx,bhitpos.y+dy) /* missile hits the wall */ || IS_WALL(levl[bhitpos.x+dx][bhitpos.y+dy].typ) || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SDOOR || levl[bhitpos.x+dx][bhitpos.y+dy].typ == SCORR #ifdef SINKS /* Thrown objects "sink" */ || IS_SINK(levl[bhitpos.x][bhitpos.y].typ) #endif ) { drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); break; } tmp_at(bhitpos.x, bhitpos.y); } tmp_at(bhitpos.x, bhitpos.y); tmp_at(-1, -1); /* blindfold keeps substances out of your eyes */ if (blindinc && !Blindfolded) { u.ucreamed += blindinc; make_blinded(Blinded + blindinc,FALSE); } } /* Remove an item from the monster's inventory. */ void m_useup(mon, obj) struct monst *mon; struct obj *obj; { struct obj *otmp, *prev; if (obj->quan > 1) { obj->quan--; return; } prev = ((struct obj *) 0); for (otmp = mon->minvent; otmp; otmp = otmp->nobj) { if (otmp == obj) { if (prev) prev->nobj = obj->nobj; else mon->minvent = obj->nobj; free((genericptr_t) obj); break; } prev = otmp; } } #endif /* OVLB */ #ifdef OVL1 /* Always returns 0??? -SAC */ int thrwmu(mtmp) /* monster throws item at you */ register struct monst *mtmp; { struct obj *otmp, *select_rwep(); register xchar x, y; if(lined_up(mtmp)) { if((otmp = select_rwep(mtmp))) { /* If you are coming toward the monster, the monster * should try to soften you up with missiles. If you are * going away, you are probably hurt or running. Give * chase, but if you are getting too far away, throw. */ x = mtmp->mx; y = mtmp->my; if(!URETREATING(x,y) || !rn2(BOLT_LIM-movedist(x,mtmp->mux,y,mtmp->muy))) { int savequan = otmp->quan; const char *verb = "throws"; if (otmp->otyp == ARROW #ifdef TOLKIEN || otmp->otyp == ELVEN_ARROW || otmp->otyp == ORCISH_ARROW #endif || otmp->otyp == CROSSBOW_BOLT) verb = "shoots"; otmp->quan = 1; if (canseemon(mtmp)) pline("%s %s %s!", Monnam(mtmp), verb, an(xname(otmp))); otmp->quan = savequan; m_throw(mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), movedist(mtmp->mx,mtmp->mux,mtmp->my,mtmp->muy), otmp); if (!otmp->quan) m_useup(mtmp, otmp); nomul(0); return 0; } } } return 0; } #endif /* OVL1 */ #ifdef OVLB int spitmu(mtmp, mattk) /* monster spits substance at you */ register struct monst *mtmp; register struct attack *mattk; { register struct obj *otmp; if(mtmp->mcan) { if(flags.soundok) pline("A dry rattle comes from %s's throat", mon_nam(mtmp)); return 0; } if(lined_up(mtmp)) { switch (mattk->adtyp) { case AD_BLND: case AD_DRST: otmp = mksobj(BLINDING_VENOM, FALSE); break; default: impossible("bad attack type in spitmu"); /* fall through */ case AD_ACID: otmp = mksobj(ACID_VENOM, FALSE); break; } if(!rn2(BOLT_LIM-movedist(mtmp->mx,mtmp->mux,mtmp->my,mtmp->muy))) { if (canseemon(mtmp)) pline("%s spits venom!", Monnam(mtmp)); m_throw(mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), movedist(mtmp->mx,mtmp->mux,mtmp->my,mtmp->muy), otmp); nomul(0); return 0; } } return 0; } #endif /* OVLB */ #ifdef OVL1 int breamu(mtmp, mattk) /* monster breathes at you (ranged) */ register struct monst *mtmp; register struct attack *mattk; { if(lined_up(mtmp)) { if(mtmp->mcan) { if(flags.soundok) { if(canseemon(mtmp)) pline("%s coughs.", Monnam(mtmp)); else You("hear a cough."); } return(0); } if(rn2(3)) { if((mattk->adtyp >= 1) && (mattk->adtyp < 11)) { if(canseemon(mtmp)) pline("%s breathes %s!", Monnam(mtmp), breathwep[mattk->adtyp-1]); buzz((int) (-20 - (mattk->adtyp-1)), (int)mattk->damn, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); nomul(0); } else impossible("Breath weapon %d used", mattk->adtyp-1); } } return(1); } boolean linedup(ax, ay, bx, by) register xchar ax, ay, bx, by; { register xchar x, y; tbx = ax - bx; /* These two values are set for use */ tby = ay - by; /* after successful return. */ if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */ && movedist(tbx, 0, tby, 0) < BOLT_LIM) { /* Check if there are any dead squares between. If so, * it will not be possible to shoot. */ x = bx; y = by; while(x != ax || y != ay) { if(!accessible(x, y)) return FALSE; x += sgn(tbx), y += sgn(tby); } return TRUE; } return FALSE; } boolean lined_up(mtmp) /* is mtmp in position to use ranged attack? */ register struct monst *mtmp; { return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my)); } #endif /* OVL1 */ #ifdef OVL0 /* Check if a monster is carrying a particular item. */ struct obj * m_carrying(mtmp, type) struct monst *mtmp; int type; { register struct obj *otmp; for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if(otmp->otyp == type) return(otmp); return((struct obj *) 0); } #endif /* OVL0 */ #ifdef OVL1 XSTATIC int movedist(x0, x1, y0, y1) int x0, x1, y0, y1; { register int absdx, absdy; absdx = abs(x1 - x0); absdy = abs(y1 - y0); return (max(absdx,absdy)); } #endif /* OVL1 */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.