This is mhitm.c in view mode; [Download] [Up]
/* SCCS Id: @(#)mhitm.c 3.0 89/11/27 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef NAMED_ITEMS # include "artifact.h" #endif #ifdef OVLB static boolean vis, far_noise; static long noisetime; static struct obj *otmp; #endif /* OVLB */ static void FDECL(mrustm, (struct monst *, struct monst *, struct obj *)); static int FDECL(hitmm, (struct monst *,struct monst *,struct attack *)); static int FDECL(gazemm, (struct monst *,struct monst *,struct attack *)); static int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *)); static int FDECL(explmm, (struct monst *,struct monst *,struct attack *)); static int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *)); static void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *)); static void FDECL(noises,(struct monst *,struct attack *)); static void FDECL(missmm,(struct monst *,struct monst *,struct attack *)); #ifdef OVLB static void noises(magr, mattk) register struct monst *magr; register struct attack *mattk; { boolean farq = (dist(magr->mx, magr->my) > 15); if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) { far_noise = farq; noisetime = moves; You("hear %s%s.", (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises", farq ? " in the distance" : ""); } } static void missmm(magr, mdef, mattk) register struct monst *magr, *mdef; struct attack *mattk; { char buf[BUFSZ]; if(vis) { if(mdef->mimic) seemimic(mdef); if(magr->mimic) seemimic(magr); if (could_seduce(magr,mdef,mattk) && !magr->mcan) Sprintf(buf, "%s pretends to be friendly to", Monnam(magr)); else Sprintf(buf,"%s misses", Monnam(magr)); pline("%s %s.", buf, mon_nam(mdef)); } else noises(magr, mattk); } /* * fightm returns 3 if no attack, otherwise the results of mattackm */ int fightm(mtmp) /* have monsters fight each other */ register struct monst *mtmp; { register struct monst *mon, *nmon; #ifdef LINT nmon = 0; #endif for(mon = fmon; mon; mon = nmon) { nmon = mon->nmon; if(nmon == mtmp) nmon = mtmp->nmon; if(mon != mtmp) { if(dist2(mon->mx,mon->my,mtmp->mx,mtmp->my) < 3) /* note: grid bug check needed here as well as in mattackm */ if(mtmp->data != &mons[PM_GRID_BUG] || mtmp->mx==mon->mx || mtmp->my==mon->my) return(mattackm(mtmp,mon)); } } return(3); } /* * mattackm returns -1 (magr died), 0 (miss), 1 (mdef hit), or 2 (mdef killed) * * Each successive attack has a lower probability of hitting. Some * rely on the success of previous attacks. * * In the case of exploding monsters, the monster dies as well. */ int mattackm(magr, mdef) register struct monst *magr,*mdef; { int i, tmp, nsum, sum[NATTK]; struct attack *mattk; struct permonst *pa, *pd; schar strike; if(!magr || !mdef) return(0); /* mike@genat */ pa = magr->data; pd = mdef->data; if(!magr->mcanmove) return(0); /* riv05!a3 */ if(pa==&mons[PM_GRID_BUG] && magr->mx != mdef->mx && magr->my != mdef->my) return(0); /* Calculate the armour class differential. */ tmp = pd->ac + magr->m_lev; if(mdef->mconf || !mdef->mcanmove || mdef->msleep){ tmp += 4; if(mdef->msleep) mdef->msleep = 0; } if (is_elf(magr->data) && is_orc(mdef->data)) tmp++; /* Set up visibility of action */ vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my)); /* Set flag indicating monster has moved this turn. Necessary since a * monster might get an attack out of sequence (i.e. before its move) in * some cases, in which case this still counts as its move for the round * and it shouldn't move again. */ magr->mlstmv = moves; /* Now perform all attacks for the monster. */ for(i=0; i<NATTK; i++) sum[i] = 0; for(i = nsum = 0; i < NATTK; nsum |= sum[i++]) { mattk = &(pa->mattk[i]); otmp = (struct obj *)0; switch(mattk->aatyp) { case AT_WEAP: /* "hand to hand" attacks */ otmp = select_hwep(magr); if(otmp) { if (vis) mswingsm(magr, mdef, otmp); tmp += hitval(otmp, pd); } case AT_CLAW: case AT_KICK: case AT_BITE: case AT_STNG: case AT_TUCH: case AT_BUTT: if((strike = (tmp > rnd(20+i)))) { sum[i] = hitmm(magr, mdef, mattk); if(sum[i] == -1) return(-1); } else missmm(magr, mdef, mattk); break; case AT_HUGS: /* automatic if prev two attacks succeed */ strike = 1; if(sum[i-1] && sum[i-2]) { sum[i] = hitmm(magr, mdef, mattk); if(sum[i] == -1) return(-1); } break; case AT_GAZE: /* will not wake up a sleeper */ strike = 0; sum[i] = gazemm(magr, mdef, mattk); break; case AT_EXPL: /* automatic hit if next to */ strike = -1; sum[i] = explmm(magr, mdef, mattk); break; case AT_ENGL: if((strike = (tmp > rnd(20+i)))) sum[i]= gulpmm(magr, mdef, mattk); else missmm(magr, mdef, mattk); break; default: /* no attack */ strike = 0; break; } if(sum[i] == 2) return(2); /* defender dead */ if(strike) mdef->msleep = 0; if(strike == -1) return(-1); /* attacker dead */ nsum |= sum[i]; } return(nsum); } /* hitmm returns 0 (miss), 1 (hit), 2 (kill), or -1 (magr died) */ static int hitmm(magr, mdef, mattk) register struct monst *magr,*mdef; struct attack *mattk; { if(vis){ int compat; char buf[BUFSZ]; if(mdef->mimic) seemimic(mdef); if(magr->mimic) seemimic(magr); if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) { Sprintf(buf, "%s %s", Monnam(magr), mdef->mcansee ? "smiles at" : "talks to"); pline("%s %s %s.", buf, mon_nam(mdef), compat == 2 ? "engagingly" : "seductively"); } else { switch (mattk->aatyp) { case AT_BITE: Sprintf(buf,"%s bites", Monnam(magr)); break; case AT_STNG: Sprintf(buf,"%s stings", Monnam(magr)); break; case AT_BUTT: Sprintf(buf,"%s butts", Monnam(magr)); break; case AT_TUCH: Sprintf(buf,"%s touches", Monnam(magr)); break; case AT_HUGS: if (magr != u.ustuck) { Sprintf(buf,"%s squeezes", Monnam(magr)); break; } default: Sprintf(buf,"%s hits", Monnam(magr)); } } pline("%s %s.", buf, mon_nam(mdef)); } else noises(magr, mattk); return(mdamagem(magr, mdef, mattk)); } static int gazemm(magr, mdef, mattk) register struct monst *magr, *mdef; struct attack *mattk; { char buf[BUFSZ]; if(vis) { Sprintf(buf,"%s gazes at", Monnam(magr)); pline("%s %s.", buf, mon_nam(mdef)); } if (!mdef->mcansee || mdef->msleep) { if(vis) pline("but nothing happens."); return(0); } return(mdamagem(magr, mdef, mattk)); } static int gulpmm(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { int mx, my, tmp; char buf[BUFSZ]; if(mdef->data->msize >= MZ_HUGE) return 0; if(vis) { Sprintf(buf,"%s swallows", Monnam(magr)); pline("%s %s.", buf, mon_nam(mdef)); } mx = magr->mx; my = magr->my; /* move over top of the defender */ if(cansee(mdef->mx, mdef->my)) unpmon(mdef); if(cansee(magr->mx, magr->my)) unpmon(magr); magr->mx = mdef->mx; magr->my = mdef->my; if(cansee(magr->mx, magr->my)) pmon(magr); if((tmp = mdamagem(magr, mdef, mattk)) == 2) { remove_monster(mx, my); place_monster(magr, magr->mx, magr->my); /* if mdamagem left a corpse it erased magr's symbol */ unpmon(magr); pmon(magr); return(2); /* defender died */ } else { /* defender survived */ if(cansee(mdef->mx, mdef->my)) pline("%s is regurgitated!", Monnam(mdef)); if(cansee(magr->mx, magr->my)) unpmon(magr); magr->mx = mx; magr->my = my; /* move off of defender */ if(cansee(magr->mx, magr->my)) pmon(magr); if(cansee(mdef->mx, mdef->my)) pmon(mdef); nscr(); return(tmp); } } static int explmm(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { if(cansee(magr->mx, magr->my)) pline("%s explodes!", Monnam(magr)); else noises(magr, mattk); (void) mdamagem(magr, mdef, mattk); if(magr->mtame) You("have a sad feeling for a moment, then it passes."); mondead(magr); return(2); } static const char psf[] = "have a peculiarly sad feeling for a moment, then it passes."; static int mdamagem(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { struct permonst *ptr, *pd = mdef->data; int tmp = d((int)mattk->damn,(int)mattk->damd); char buf[BUFSZ]; if(mdef->data == &mons[PM_COCKATRICE] && !resists_ston(magr->data) && (mattk->aatyp != AT_WEAP || !otmp) && (mattk->aatyp != AT_GAZE && mattk->aatyp != AT_EXPL) && (!is_mercenary(magr->data) || !m_carrying(magr, LEATHER_GLOVES))) { /* Note: other monsters may carry gloves, only soldiers have them */ /* as their "armor" and can be said to wear them */ if (vis) pline("%s turns to stone!", Monnam(magr)); else if (magr->mtame) You(psf); monstone(magr); return -1; } switch(mattk->adtyp) { case AD_DGST: if(flags.verbose && flags.soundok) verbalize("Burrrrp!"); tmp = mdef->mhp; break; case AD_STUN: if (magr->mcan) break; if(vis) pline("%s staggers for a moment.", Monnam(mdef)); mdef->mstun = 1; /* fall through */ case AD_WERE: case AD_HEAL: case AD_LEGS: case AD_PHYS: if (mattk->aatyp == AT_KICK && thick_skinned(mdef->data)) tmp = 0; else if(mattk->aatyp == AT_WEAP) { if(otmp) { tmp += dmgval(otmp, pd); #ifdef NAMED_ITEMS if(spec_ability(otmp, SPFX_DRLI) && !resists_drli(mdef->data)) { int dam = rnd(8); tmp += dam; if(vis) pline("The %s blade drains the life from %s!", Hallucination ? hcolor() : black, mon_nam(mdef)); mdef->mhpmax -= dam; if (mdef->m_lev == 0) tmp = mdef->mhp; else mdef->m_lev--; } #endif mrustm(magr, mdef, otmp); } } break; case AD_FIRE: if (magr->mcan) { tmp = 0; break; } #ifdef GOLEMS golemeffects(mdef, AD_FIRE, tmp); #endif /* GOLEMS */ if(vis) pline("%s is on fire!", Monnam(mdef)); if(resists_fire(pd)) { pline("The fire doesn't seem to burn %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); tmp = 0; } else { tmp += destroy_mitem(mdef, SCROLL_SYM, AD_FIRE); tmp += destroy_mitem(mdef, POTION_SYM, AD_FIRE); #ifdef SPELLS tmp += destroy_mitem(mdef, SPBOOK_SYM, AD_FIRE); #endif } break; case AD_COLD: if (magr->mcan) { tmp = 0; break; } #ifdef GOLEMS golemeffects(mdef, AD_COLD, tmp); #endif /* GOLEMS */ if(vis) pline("%s is covered in frost!", Monnam(mdef)); if(resists_cold(pd)) { pline("The frost doesn't seem to chill %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); tmp = 0; } else tmp += destroy_mitem(mdef, POTION_SYM, AD_COLD); break; case AD_ELEC: if (magr->mcan) { tmp = 0; break; } #ifdef GOLEMS golemeffects(mdef, AD_ELEC, tmp); #endif /* GOLEMS */ if(vis) pline("%s gets zapped!", Monnam(mdef)); if(resists_elec(pd)) { pline("The zap doesn't shock %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); tmp = 0; } break; case AD_ACID: if (magr->mcan) { tmp = 0; break; } if(resists_acid(pd)) { pline("%s is covered in acid, but it seems harmless.", Monnam(mdef)); tmp = 0; } else { pline("%s is covered in acid!", Monnam(mdef)); pline("It burns %s!", mon_nam(mdef)); } break; case AD_RUST: #ifdef GOLEMS if (!magr->mcan && pd == &mons[PM_IRON_GOLEM]) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); else if(mdef->mtame) pline("May %s rust in peace.", mon_nam(mdef)); mondied(mdef); magr->mhpmax += 1 + rn2((int)mdef->m_lev+1); ptr = grow_up(magr); if(!ptr) return(-1); return(2); } #endif /* GOLEMS */ tmp = 0; break; case AD_DCAY: #ifdef GOLEMS if (!magr->mcan && (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM])) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); else if(mdef->mtame) pline("May %s rot in peace.", mon_nam(mdef)); mondied(mdef); magr->mhpmax += 1 + rn2((int)mdef->m_lev+1); ptr = grow_up(magr); if(!ptr) return(-1); return(2); } #endif /* GOLEMS */ tmp = 0; break; case AD_STON: if(!resists_ston(pd)) { magr->mhpmax += 1 + rn2((int)mdef->m_lev+1); if(vis) pline("%s turns to stone!", Monnam(mdef)); else if(mdef->mtame) You(psf); monstone(mdef); ptr = grow_up(magr); if(!ptr) return(-1); return(2); } tmp = 0; /* no damage if this fails */ break; case AD_TLPT: if(!magr->mcan && tmp < mdef->mhp) { rloc(mdef); if(vis && !cansee(mdef->mx, mdef->my)) pline("%s suddenly disappears!", Monnam(mdef)); } break; case AD_SLEE: if(!resists_sleep(pd) && !magr->mcan && !mdef->msleep && mdef->mcanmove) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is put to sleep by %s.", buf, mon_nam(magr)); } mdef->mcanmove = 0; mdef->mfrozen = rnd(10); } break; case AD_PLYS: if(!magr->mcan && mdef->mcanmove) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is frozen by %s.", buf, mon_nam(magr)); } mdef->mcanmove = 0; mdef->mfrozen = rnd(10); } break; case AD_SLOW: if(!magr->mcan && vis && mdef->mspeed != MSLOW) { if (vis) pline("%s slows down.", Monnam(mdef)); if (mdef->mspeed == MFAST) mdef->mspeed = 0; else mdef->mspeed = MSLOW; } break; case AD_CONF: /* Since confusing another monster doesn't have a real time * limit, setting spec_used would not really be right (though * we still should check for it). */ if(!magr->mcan && vis && !mdef->mconf && !magr->mspec_used) { pline("%s looks confused.", Monnam(mdef)); mdef->mconf = 1; } break; case AD_BLND: if(!magr->mcan && haseyes(pd)) { if(vis && mdef->mcansee) pline("%s is blinded.", Monnam(mdef)); { register unsigned rnd_tmp; rnd_tmp = d((int)mattk->damn, (int)mattk->damd); mdef->mcansee = 0; if((mdef->mblinded + rnd_tmp) > 127) mdef->mblinded = 127; else mdef->mblinded += rnd_tmp; } } tmp = 0; break; case AD_CURS: if(!night() && (magr->data == &mons[PM_GREMLIN])) break; if(!magr->mcan && !rn2(10)) { if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN) were_change(mdef); #ifdef GOLEMS if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (vis) { pline("Some writing vanishes from %s's head!", mon_nam(mdef)); pline("%s dies!", Monnam(mdef)); } else if (mdef->mtame) You("have a strangely sad feeling for a moment, then it passes."); mondied(mdef); magr->mhpmax += 1 + rn2((int)mdef->m_lev+1); ptr = grow_up(magr); if(!ptr) return(-1); return(2); } #endif /* GOLEMS */ mdef->mcan = 1; if (flags.soundok) { if (!vis) You("hear laughter."); else pline("%s chuckles.", Monnam(magr)); } } break; case AD_SGLD: tmp = 0; if (magr->mcan || !mdef->mgold) break; /* technically incorrect; no check for stealing gold from * between mdef's feet... */ magr->mgold += mdef->mgold; mdef->mgold = 0; if (vis) { Strcpy(buf, Monnam(magr)); pline("%s steals some gold from %s.", buf, mon_nam(mdef)); } break; case AD_DRLI: if(rn2(2) && !resists_drli(mdef->data)) { tmp = d(2,6); if (vis) kludge("%s suddenly seems weaker!", Monnam(mdef)); mdef->mhpmax -= tmp; if (mdef->m_lev == 0) tmp = mdef->mhp; else mdef->m_lev--; /* Automatic kill if drained past level 0 */ } break; #ifdef SEDUCE case AD_SSEX: #endif case AD_SITM: /* for now these are the same */ case AD_SEDU: if (!magr->mcan && mdef->minvent) { otmp = mdef->minvent; mdef->minvent = otmp->nobj; otmp->nobj = magr->minvent; magr->minvent = otmp; if (vis) { Strcpy(buf, Monnam(magr)); pline("%s steals %s from %s!", buf, doname(otmp), mon_nam(mdef)); } } tmp = 0; break; case AD_DRST: case AD_DRDX: case AD_DRCO: if (!magr->mcan && !rn2(8)) { if (vis) pline("%s's %s was poisoned!", Monnam(magr), mattk->aatyp==AT_BITE ? "bite" : "sting"); if (resists_poison(mdef->data)) { if (vis) pline("The poison doesn't seem to affect %s.", mon_nam(mdef)); } else { if (rn2(10)) tmp += rn1(10,6); else { if (vis) pline("The poison was deadly..."); tmp = mdef->mhp; } } } break; case AD_STCK: case AD_WRAP: /* monsters cannot grab one another, it's too hard */ break; default: tmp = 0; break; } if(!tmp) return(1); if((mdef->mhp -= tmp) < 1) { magr->mhpmax += 1 + rn2((int)mdef->m_lev+1); if(vis) pline("%s is %s!", Monnam(mdef), (is_demon(mdef->data) || is_undead(mdef->data)) ? "destroyed" : "killed"); else if(mdef->mtame) You("have a sad feeling for a moment, then it passes."); mondied(mdef); ptr = grow_up(magr); if(!ptr) return(-1); return(2); } /* fixes a bug where max monster hp could overflow. */ if(magr->mhpmax <= 0 || magr->mhpmax > MHPMAX) magr->mhpmax = MHPMAX; return(1); } #endif /* OVLB */ #ifdef OVL0 int noattacks(ptr) /* returns 1 if monster doesn't attack */ struct permonst *ptr; { int i; for(i = 0; i < NATTK; i++) if(ptr->mattk[i].aatyp) return(0); return(1); } #endif /* OVL0 */ #ifdef OVLB static void mrustm(magr, mdef, obj) register struct monst *magr, *mdef; register struct obj *obj; { if (!magr || !mdef || !obj) return; /* just in case */ if (mdef->data == &mons[PM_RUST_MONSTER] && objects[obj->otyp].oc_material == METAL && !obj->rustfree && obj->spe > -2) { if(obj->blessed && rn2(3)) { if (cansee(mdef->mx, mdef->my)) pline("%s's weapon is not affected.", Monnam(magr)); } else { if (cansee(mdef->mx, mdef->my)) pline("%s's %s!", Monnam(magr), aobjnam(obj, "corrode")); obj->spe--; } } } static void mswingsm(magr, mdef, otemp) register struct monst *magr, *mdef; register struct obj *otemp; { char buf[BUFSZ]; Strcpy(buf, mon_nam(mdef)); if (!flags.verbose || Blind || otemp->olet != WEAPON_SYM) return; pline("%s %s %s %s at %s.", Monnam(magr), ((otemp->otyp >= SPEAR && otemp->otyp <= LANCE) || (otemp->otyp >= PARTISAN && otemp->otyp <= SPETUM) || otemp->otyp == TRIDENT) ? "thrusts" : "swings", is_female(magr) ? "her" : is_human(magr->data) ? "his" : "its", xname(otemp), buf); } #endif /* OVLB */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.