This is uhitm.c in view mode; [Download] [Up]
/* SCCS Id: @(#)uhitm.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 static boolean hitum(); #ifdef POLYSELF static boolean hmonas(); #endif static void nohandglow(); #ifdef WORM extern boolean notonhead; #endif struct monst * clone_mon(mon) struct monst *mon; { coord mm; struct monst *m2; mm.x = mon->mx; mm.y = mon->my; enexto(&mm, mm.x, mm.y, mon->data); if (MON_AT(mm.x, mm.y) || mon->mhp <= 1) return (struct monst *)0; m2 = newmonst(0); *m2 = *mon; /* copy condition of old monster */ m2->nmon = fmon; fmon = m2; m2->m_id = flags.ident++; m2->mx = mm.x; m2->my = mm.y; m2->minvent = (struct obj *) 0; /* objects don't clone */ m2->mleashed = FALSE; m2->mgold = 0L; /* Max HP the same, but current HP halved for both. The caller * might want to override this by halving the max HP also. */ m2->mhpmax = mon->mhpmax; m2->mhp = mon->mhp /= 2; /* since shopkeepers and guards will only be cloned if they've been * polymorphed away from their original forms, the clone doesn't have * room for the extra information. we also don't want two shopkeepers * around for the same shop. * similarly, clones of named monsters don't have room for the name, * so we just make the clone unnamed instead of bothering to create * a clone with room and copying over the name from the right place * (which changes if the original was a shopkeeper or guard). */ if (mon->isshk) m2->isshk = FALSE; if (mon->isgd) m2->isgd = FALSE; #if defined(ALTARS) && defined(THEOLOGY) if (mon->ispriest) m2->ispriest = FALSE; #endif m2->mxlth = 0; m2->mnamelth = 0; m2->mdispl = 0; pmon(m2); /* display the new monster */ place_monster(m2, m2->mx, m2->my); if (mon->mtame) (void) tamedog(m2, (struct obj *)0); return m2; } boolean special_case(mtmp) /* Moved this code from attack() in order to */ /* avoid having to duplicate it in dokick. */ register struct monst *mtmp; { if (flags.confirm && (mtmp->mpeaceful || mtmp->mtame) && !Confusion && !Hallucination && (!mtmp->mhide || !mtmp->mundetected) && (!mtmp->mimic || Protection_from_shape_changers)) { if (Blind ? Telepat : (!mtmp->minvis || See_invisible)) { #ifdef MACOS char mac_tbuf[80]; if(!flags.silent) SysBeep(1); sprintf(mac_tbuf, "Really attack %s?", mon_nam(mtmp)); if(UseMacAlertText(128, mac_tbuf) != 1) { #else pline("Really attack %s? ", mon_nam(mtmp)); (void) fflush(stdout); if (yn() != 'y') { #endif flags.move = 0; return(TRUE); } } } if(mtmp->mimic && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp); return(TRUE); } if(mtmp->mhide && mtmp->mundetected && !canseemon(mtmp)) { mtmp->mundetected = 0; if (!(Blind ? Telepat : (HTelepat & WORN_HELMET))) { register struct obj *obj; if(Blind) pline("Wait! There's a hidden monster there!"); else if(OBJ_AT(mtmp->mx, mtmp->my)) { if(obj = level.objects[mtmp->mx][mtmp->my]) pline("Wait! There's %s hiding under %s!", defmonnam(mtmp), doname(obj)); } else if (levl[mtmp->mx][mtmp->my].gmask == 1) pline("Wait! There's %s hiding under some gold!", defmonnam(mtmp)); wakeup(mtmp); return(TRUE); } } return(FALSE); } schar find_roll_to_hit(mtmp) register struct monst *mtmp; { schar tmp; struct permonst *mdat = mtmp->data; #ifdef POLYSELF tmp = Luck + mdat->ac + abon() + ((u.umonnum >= 0) ? uasmon->mlevel : u.ulevel); #else tmp = Luck + u.ulevel + mdat->ac + abon(); #endif /* it is unchivalrous to attack the defenseless or from behind */ if (pl_character[0] == 'K' && u.ualigntyp == U_LAWFUL && (!mtmp->mcanmove || mtmp->msleep || mtmp->mflee) && u.ualign > -10) adjalign(-1); /* Adjust vs. (and possibly modify) monster state. */ if(mtmp->mstun) tmp += 2; if(mtmp->mflee) tmp += 2; if(mtmp->msleep) { mtmp->msleep = 0; tmp += 2; } if(!mtmp->mcanmove) { tmp += 4; if(!rn2(10)) { mtmp->mcanmove = 1; mtmp->mfrozen = 0; } } if (is_orc(mtmp->data) && pl_character[0]=='E') tmp++; /* with a lot of luggage, your agility diminishes */ tmp -= (inv_weight() + 40)/20; if(u.utrap) tmp -= 3; #ifdef POLYSELF /* Some monsters have a combination of weapon attacks and non-weapon * attacks. It is therefore wrong to add hitval to tmp; we must add it * only for the specific attack (in hmonas()). */ if(uwep && u.umonnum == -1) tmp += hitval(uwep, mdat); #else if(uwep) tmp += hitval(uwep, mdat); #endif return tmp; } /* try to attack; return FALSE if monster evaded */ /* u.dx and u.dy must be set */ boolean attack(mtmp) register struct monst *mtmp; { schar tmp = 0; register struct permonst *mdat = mtmp->data; if(unweapon) { unweapon=FALSE; if(flags.verbose) if(uwep) You("begin bashing monsters with your %s.", aobjnam(uwep, NULL)); else #ifdef POLYSELF if (!cantwield(uasmon)) #endif You("begin bashing monsters with your %s hands.", uarmg ? "gloved" : "bare"); /* Del Lamb */ } /* andrew@orca: prevent unlimited pick-axe attacks */ u_wipe_engr(3); if(mdat->mlet == S_LEPRECHAUN && mtmp->mfrozen && !mtmp->msleep && !mtmp->mconf && mtmp->mcansee && !rn2(7) && (m_move(mtmp, 0) == 2 || /* he died */ mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy)) /* he moved */ return(FALSE); /* This section of code provides protection against accidentally * hitting peaceful (like '@') and tame (like 'd') monsters. * There is protection only if you're not blind, confused, or hallu- * cinating. */ /* changes by wwp 5/16/85 */ if (!Confusion && !Hallucination && flags.safe_dog && (Blind ? Telepat : (!mtmp->minvis || See_invisible)) && mtmp->mtame) { mtmp->mflee = 1; mtmp->mfleetim = rnd(6); if (mtmp->mnamelth) You("stop to avoid hitting %s.", NAME(mtmp)); else You("stop to avoid hitting your %s.", mdat->mname); return(TRUE); } /* moved code to a separate function to share with dokick */ if(special_case(mtmp)) return(TRUE); #ifdef POLYSELF if(u.umonnum >= 0) { /* certain "pacifist" monsters don't attack */ set_uasmon(); if(noattacks(uasmon)) { You("have no way to attack monsters physically."); return(TRUE); } } #endif tmp = find_roll_to_hit(mtmp); #ifdef POLYSELF if (u.umonnum >= 0) (void) hmonas(mtmp, tmp); else #endif (void) hitum(mtmp, tmp); return(TRUE); } static boolean known_hitum(mon, mhit) /* returns TRUE if monster still lives */ /* Made into a separate function because in some cases we want to know * in the calling function whether we hit. */ register struct monst *mon; register int mhit; { register boolean malive = TRUE; stoned = FALSE; /* this refers to the thing hit, not you */ if(!mhit) { if(!Blind && flags.verbose) You("miss %s.", mon_nam(mon)); else You("miss it."); if(!mon->msleep && mon->mcanmove) wakeup(mon); } else { /* we hit the monster; be careful: it might die! */ #ifdef WORM if (mon->mx != u.ux+u.dx || mon->my != u.uy+u.dy) notonhead = TRUE; #endif if((malive = hmon(mon, uwep, 0)) == TRUE) { /* monster still alive */ if(!rn2(25) && mon->mhp < mon->mhpmax/2) { mon->mflee = 1; if(!rn2(3)) mon->mfleetim = rnd(100); if(u.ustuck == mon && !u.uswallow #ifdef POLYSELF && !sticks(uasmon) #endif ) u.ustuck = 0; } #ifdef WORM if(mon->wormno) cutworm(mon, u.ux+u.dx, u.uy+u.dy, uwep ? uwep->otyp : 0); #endif } #if defined(ALTARS) && defined(THEOLOGY) if(mon->ispriest && !rn2(2)) ghod_hitsu(); #endif } return(malive); } static boolean hitum(mon, tmp) /* returns TRUE if monster still lives */ struct monst *mon; int tmp; { static int malive; boolean mhit = (tmp > rnd(20) || u.uswallow); malive = known_hitum(mon, mhit); (void) passive(mon, mhit, malive, FALSE); return(malive); } boolean /* general "damage monster" routine */ hmon(mon, obj, thrown) /* return TRUE if mon still alive */ register struct monst *mon; register struct obj *obj; register int thrown; { register int tmp; struct permonst *mdat = mon->data; /* Why all these booleans? This stuff has to be done in the * following order: * 1) Know what we're attacking with, and print special hittxt for * unusual cases. * 2a) Know whether we did damage (depends on 1) * 2b) Know if it's poisoned (depends on 1) * 2c) Know whether we get a normal damage bonus or not (depends on 1) * 3a) Know what the value of the damage bonus is (depends on 2c) * 3b) Know how much poison damage was taken (depends on 2b) and if the * poison instant-killed it * 4) Know if it was killed (requires knowing 3a, 3b) except by instant- * kill poison * 5) Print hit message (depends on 1 and 4) * 6a) Print poison message (must be done after 5) #if 0 * 6b) Rust weapon (must be done after 5) #endif * 7) Possibly kill monster (must be done after 6a, 6b) * 8) Instant-kill from poison (can happen anywhere between 5 and 9) * 9) Hands not glowing (must be done after 7 and 8) * The major problem is that since we don't want a "hit" message * when the monster dies, we have to know how much damage it did * _before_ outputting a hit message, but any messages associated with * the damage don't come out until _after_ outputting a hit message. */ boolean hittxt = FALSE, destroyed = FALSE; boolean get_dmg_bonus = TRUE; boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE; boolean silvermsg = FALSE; wakeup(mon); if(!obj) { tmp = rnd(2); /* attack with bare hands */ #if 0 if(mdat == &mons[PM_COCKATRICE] && !uarmg #ifdef POLYSELF && !resists_ston(uasmon) #endif ) { kludge("You hit %s with your bare %s.", mon_nam(mon), makeplural(body_part(HAND))); You("turn to stone..."); done_in_by(mon); hittxt = TRUE; /* maybe lifesaved */ } #endif } else { if(obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE || obj->otyp == UNICORN_HORN || obj->olet == ROCK_SYM) { if(obj == uwep && (obj->otyp >= BOW || obj->otyp < BOOMERANG) && obj->otyp != PICK_AXE && obj->otyp != UNICORN_HORN) tmp = rnd(2); else { tmp = dmgval(obj, mdat); #ifdef NAMED_ITEMS if(spec_ability(obj, SPFX_DRLI) && !resists_drli(mdat)) { if (!Blind) { pline("The %s blade draws the life from %s!", Hallucination ? hcolor() : black, mon_nam(mon)); hittxt = TRUE; } if (mon->m_lev == 0) tmp = mon->mhp; else { int drain = rnd(8); tmp += drain; mon->mhpmax -= drain; mon->m_lev--; } } #endif if(!thrown && obj == uwep && obj->otyp == BOOMERANG && !rnl(3)) { kludge("As you hit %s, the boomerang breaks into splinters.", mon_nam(mon)); useup(obj); hittxt = TRUE; tmp++; } if(thrown && (obj->otyp >= ARROW && obj->otyp <= SHURIKEN)){ if(((uwep && objects[obj->otyp].w_propellor == -objects[uwep->otyp].w_propellor) || obj->otyp==DART || obj->otyp==SHURIKEN) && obj->opoisoned) ispoisoned = TRUE; } if(thrown && obj->otyp == SILVER_ARROW) { if (is_were(mdat) || mdat->mlet==S_VAMPIRE || (mdat->mlet==S_IMP && mdat != &mons[PM_TENGU]) || is_demon(mdat)) { silvermsg = TRUE; tmp += rnd(20); } } } } else if(obj->olet == POTION_SYM) { if (obj->quan > 1) setuwep(splitobj(obj, 1)); else setuwep((struct obj *)0); freeinv(obj); potionhit(mon,obj); hittxt = TRUE; tmp = 1; } else switch(obj->otyp) { case HEAVY_IRON_BALL: tmp = rnd(25); break; case BOULDER: tmp = rnd(20); break; #ifdef MEDUSA case MIRROR: You("break your mirror. That's bad luck!"); change_luck(-2); useup(obj); hittxt = TRUE; tmp = 1; #endif case EXPENSIVE_CAMERA: You("succeed in destroying your camera. Congratulations!"); useup(obj); return(TRUE); case CORPSE: /* fixed by polder@cs.vu.nl */ if(obj->corpsenm == PM_COCKATRICE) { kludge("You hit %s with the cockatrice corpse.", mon_nam(mon)); if(resists_ston(mdat)) { tmp = 1; hittxt = TRUE; break; } kludge("%s turns to stone.", Monnam(mon)); stoned = TRUE; xkilled(mon,0); nohandglow(); return(FALSE); } tmp = mons[obj->corpsenm].msize + 1; break; case EGG: /* only possible if hand-to-hand */ if(obj->corpsenm > -1 && obj->corpsenm != PM_COCKATRICE && mdat == &mons[PM_COCKATRICE]) { kludge("You hit %s with the %s egg%s.", mon_nam(mon), mons[obj->corpsenm].mname, plur((long)obj->quan)); hittxt = TRUE; pline("The egg%sn't live any more...", (obj->quan==1) ? " is" : "s are"); obj->otyp = ROCK; obj->olet = GEM_SYM; obj->known = obj->dknown = 0; obj->owt = weight(obj); } tmp = 1; break; case CLOVE_OF_GARLIC: /* no effect against demons */ if(is_undead(mdat)) mon->mflee = 1; tmp = 1; break; case CREAM_PIE: #ifdef POLYSELF case BLINDING_VENOM: if(Blind) pline(obj->otyp==CREAM_PIE ? "Splat!" : "Splash!"); else if (obj->otyp == BLINDING_VENOM) pline("The venom blinds %s%s!", mon_nam(mon), mon->mcansee ? "" : " further"); #else if(Blind) pline("Splat!"); #endif else pline("The cream pie splashes over %s%s!", mon_nam(mon), (haseyes(mdat) && mdat != &mons[PM_FLOATING_EYE]) ? "'s face" : ""); if(mon->msleep) mon->msleep = 0; setmangry(mon); mon->mcansee = 0; tmp = rnd(25) + 20; if((mon->mblinded + tmp) > 127) mon->mblinded = 127; else mon->mblinded += tmp; hittxt = TRUE; get_dmg_bonus = FALSE; tmp = 0; break; #ifdef POLYSELF case ACID_VENOM: /* only possible if thrown */ if(resists_acid(mdat)) { kludge("Your venom hits %s harmlessly.", mon_nam(mon)); tmp = 0; } else { kludge("Your venom burns %s!", mon_nam(mon)); tmp = dmgval(obj, mdat); } hittxt = TRUE; get_dmg_bonus = FALSE; break; #endif default: /* non-weapons can damage because of their weight */ /* (but not too much) */ tmp = obj->owt/10; if(tmp < 1) tmp = 1; else tmp = rnd(tmp); if(tmp > 6) tmp = 6; } } /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) * *OR* if attacking bare-handed!! */ if (get_dmg_bonus) { tmp += u.udaminc; /* If you throw using a propellor, you don't get a strength * bonus but you do get an increase-damage bonus. */ if(!thrown || !obj || !uwep || (obj->olet != GEM_SYM && obj->olet != WEAPON_SYM) || !objects[obj->otyp].w_propellor || (objects[obj->otyp].w_propellor != -objects[uwep->otyp].w_propellor)) tmp += dbon(); } /* TODO: Fix this up. multiple engulf attacks now exist. if(u.uswallow) { if((tmp -= u.uswldtim) <= 0) { Your("%s are no longer able to hit.", makeplural(body_part(ARM))); return(TRUE); } } */ if (ispoisoned) { if(resists_poison(mdat)) needpoismsg = TRUE; else if (rn2(10)) tmp += rnd(6); else poiskilled = TRUE; } if(tmp < 1) tmp = 1; mon->mhp -= tmp; if(mon->mhp < 1) destroyed = TRUE; if(mon->mtame && (!mon->mflee || mon->mfleetim)) { #ifdef SOUNDS if (rn2(8)) yelp(mon); else growl(mon); /* give them a moment's worry */ #endif mon->mtame--; mon->mflee = 1; /* Rick Richardson */ mon->mfleetim += 10*rnd(tmp); } if((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING]) && obj && obj == uwep && objects[obj->otyp].oc_material == METAL && mon->mhp > 1 && !thrown && !mon->mcan /* && !destroyed -- guaranteed by mhp > 1 */ ) { if (clone_mon(mon)) { pline("%s divides as you hit it!", Monnam(mon)); hittxt = TRUE; } } if(!hittxt && !destroyed) { if(thrown) /* thrown => obj exists */ hit(xname(obj), mon, exclam(tmp) ); else if(Blind || !flags.verbose) You("hit it."); else You("hit %s%s", mon_nam(mon), exclam(tmp)); } if (silvermsg) { if (cansee(mon->mx, mon->my)) pline("The silver arrow sears %s's flesh!", mon_nam(mon)); else pline("Its flesh is seared!"); } if (needpoismsg) kludge("The poison doesn't seem to affect %s.", mon_nam(mon)); if (poiskilled) { pline("The poison was deadly..."); xkilled(mon, 0); nohandglow(); return FALSE; } else if (destroyed) { killed(mon); /* takes care of most messages */ nohandglow(); } else if(u.umconf && !thrown) { nohandglow(); if(!resist(mon, '+', 0, NOTELL)) mon->mconf = 1; if(!mon->mstun && mon->mcanmove && !mon->msleep && !Blind && mon->mconf) pline("%s appears confused.", Monnam(mon)); } #if 0 if(mdat == &mons[PM_RUST_MONSTER] && obj && obj == uwep && objects[obj->otyp].oc_material == METAL && obj->olet == WEAPON_SYM && obj->spe > -2) { if(obj->rustfree) { pline("The rust on your %s vanishes instantly!", is_sword(obj) ? "sword" : "weapon"); } else if(obj->blessed && !rnl(4)) pline("Somehow your %s is not affected!", is_sword(obj) ? "sword" : "weapon"); else { Your("%s!", aobjnam(obj, "corrode")); obj->spe--; } } #endif return(destroyed ? FALSE : TRUE); } #ifdef POLYSELF int damageum(mdef, mattk) register struct monst *mdef; register struct attack *mattk; { register struct permonst *pd = mdef->data; register int tmp = d((int)mattk->damn, (int)mattk->damd); stoned = FALSE; if (is_demon(uasmon) && !rn2(13) && !uwep # ifdef INFERNO && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS && u.umonnum != PM_BALROG # endif ) { struct monst *dtmp; pline("Some hell-p has arrived!"); if((dtmp = makemon(!rn2(6) ? &mons[ndemon()] : uasmon, u.ux, u.uy))) (void)tamedog(dtmp, (struct obj *)0); return(0); } switch(mattk->adtyp) { case AD_STUN: if(!Blind) pline("%s staggers for a moment.", Monnam(mdef)); mdef->mstun = 1; /* fall through to next case */ case AD_WERE: /* no effect on monsters */ case AD_HEAL: case AD_LEGS: case AD_PHYS: if(mattk->aatyp == AT_WEAP) { if(uwep) tmp = 0; } else if(mattk->aatyp == AT_KICK) if(thick_skinned(mdef->data)) tmp = 0; break; case AD_FIRE: # ifdef GOLEMS golemeffects(mdef, AD_FIRE, tmp); # endif /* GOLEMS */ if(resists_fire(pd)) { shieldeff(mdef->mx, mdef->my); tmp = 0; } else { if(!Blind) pline("%s is on fire!", Monnam(mdef)); 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: # ifdef GOLEMS golemeffects(mdef, AD_COLD, tmp); # endif /* GOLEMS */ if(resists_cold(pd)) { shieldeff(mdef->mx, mdef->my); tmp = 0; } else { if(!Blind) pline("%s is covered in frost.", Monnam(mdef)); tmp += destroy_mitem(mdef, POTION_SYM, AD_COLD); } break; case AD_ELEC: # ifdef GOLEMS golemeffects(mdef, AD_ELEC, tmp); # endif /* GOLEMS */ if(resists_elec(pd)) { shieldeff(mdef->mx, mdef->my); tmp = 0; } break; case AD_ACID: if(resists_acid(pd)) tmp = 0; break; case AD_STON: if(!resists_ston(pd)) { stoned = TRUE; if(!Blind) pline("%s turns to stone.", Monnam(mdef)); xkilled(mdef, 0); return(2); } tmp = 0; /* no damage if this fails */ break; # ifdef SEDUCE case AD_SSEX: # endif case AD_SEDU: case AD_SITM: if(mdef->minvent) { struct obj *otmp, *addinv(), *stealoid; int isize = inv_cnt(); stealoid = (struct obj *)0; if(is_mercenary(pd) && could_seduce(&youmonst,mdef,mattk)){ for(otmp = mdef->minvent; otmp; otmp=otmp->nobj) if (otmp->otyp >= PLATE_MAIL && otmp->otyp <= ELVEN_CLOAK) stealoid = otmp; } if (stealoid) { boolean stolen = FALSE; /* Is "he"/"his" always correct? */ kludge("You seduce %s and he starts to take off his clothes.", mon_nam(mdef)); while(mdef->minvent) { otmp = mdef->minvent; mdef->minvent = otmp->nobj; if (!stolen && otmp==stealoid) { if(isize < 52) { otmp = addinv(otmp); /* might not increase isize */ isize = inv_cnt(); } else dropy(otmp); stealoid = otmp; stolen = TRUE; } else { if(isize < 52) { otmp = addinv(otmp); isize = inv_cnt(); You("steal: "); prinv(otmp); } else { dropy(otmp); You("steal %s.", doname(otmp)); } } } if (!stolen) impossible("Player steal fails!"); else { kludge("%s finishes taking off his suit.", Monnam(mdef)); You("steal %s!", doname(stealoid)); # ifdef ARMY mdef->data = &mons[PM_UNARMORED_SOLDIER]; # endif } } else { otmp = mdef->minvent; mdef->minvent = otmp->nobj; if(isize < 52) { otmp = addinv(otmp); You("steal: "); prinv(otmp); } else { dropy(otmp); You("steal %s.", doname(otmp)); } } } tmp = 0; break; case AD_SGLD: if (mdef->mgold) { u.ugold += mdef->mgold; mdef->mgold = 0; Your("purse feels heavier."); } tmp = 0; break; case AD_TLPT: if(tmp <= 0) tmp = 1; if(tmp < mdef->mhp) { rloc(mdef); if(!Blind) pline("%s suddenly disappears!", Monnam(mdef)); } break; case AD_BLND: if(haseyes(pd)) { if(!Blind) pline("%s is blinded.", Monnam(mdef)); mdef->mcansee = 0; mdef->mblinded += tmp; } tmp = 0; break; case AD_CURS: if (night() && !rn2(10) && !mdef->mcan) { # ifdef GOLEMS if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (!Blind) pline("Some writing vanishes from %s's head!", mon_nam(mdef)); xkilled(mdef, 0); return 2; } # endif /* GOLEMS */ mdef->mcan = 1; You("chuckle."); } tmp = 0; break; case AD_DRLI: if(rn2(2) && !resists_drli(pd)) { int xtmp = d(2,6); kludge("%s suddenly seems weaker!", Monnam(mdef)); mdef->mhpmax -= xtmp; if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev--) { kludge("%s dies!", Monnam(mdef)); xkilled(mdef,0); return(2); } } tmp = 0; break; case AD_RUST: # ifdef GOLEMS if (pd == &mons[PM_IRON_GOLEM]) { kludge("%s falls to pieces!", Monnam(mdef)); xkilled(mdef,0); return(2); } # endif /* GOLEMS */ tmp = 0; break; case AD_DCAY: # ifdef GOLEMS if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) { kludge("%s falls to pieces!", Monnam(mdef)); xkilled(mdef,0); return(2); } # endif /* GOLEMS */ case AD_DRST: case AD_DRDX: case AD_DRCO: if (!rn2(8)) { Your("%s was poisoned!", mattk->aatyp==AT_BITE ? "bite" : "sting"); if (resists_poison(mdef->data)) kludge("The poison doesn't seem to affect %s.", mon_nam(mdef)); else { if (!rn2(10)) { Your("poison was deadly..."); tmp = mdef->mhp; } else tmp += rn1(10,6); } } break; case AD_WRAP: case AD_STCK: if (!sticks(mdef->data)) u.ustuck = mdef; /* it's now stuck to you */ break; case AD_PLYS: if (mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) { if (!Blind) pline("%s is frozen by you!", Monnam(mdef)); mdef->mcanmove = 0; mdef->mfrozen = rnd(10); } break; case AD_SLEE: if (!resists_sleep(mdef->data) && !mdef->msleep && mdef->mcanmove) { if (!Blind) pline("%s suddenly falls asleep!", Monnam(mdef)); mdef->mcanmove = 0; mdef->mfrozen = rnd(10); } break; default: tmp = 0; break; } if(!tmp) return(1); if((mdef->mhp -= tmp) < 1) { if(mdef->mtame) { if(!Blind) You("killed your %s!", lmonnam(mdef) + 4); else You("feel embarrassed for a moment."); } else { if(!Blind && flags.verbose) pline("%s is killed!", Monnam(mdef)); else You("kill it!"); } xkilled(mdef, 0); return(2); } return(1); } static int explum(mdef, mattk) register struct monst *mdef; register struct attack *mattk; { switch(mattk->adtyp) { case AD_BLND: if(mdef->data->mlet != S_YLIGHT) { kludge("%s is blinded by your flash of light!", Monnam(mdef)); if (mdef->mcansee) { mdef->mblinded += rn2(25); mdef->mcansee = 0; } } break; case AD_COLD: You("explode!"); if (!resists_cold(mdef->data)) { kludge("%s gets blasted!", Monnam(mdef)); mdef->mhp -= d(6,6); if (mdef->mhp <= 0) { killed(mdef); return(2); } # ifdef GOLEMS } else if (is_golem(mdef->data)) { golemeffects(mdef, AD_COLD, d(6,6)); shieldeff(mdef->mx, mdef->my); # endif /* GOLEMS */ } else { shieldeff(mdef->mx, mdef->my); kludge("The blast doesn't seem to affect %s.", mon_nam(mdef)); } break; default: break; } return(1); } static int gulpum(mdef,mattk) register struct monst *mdef; register struct attack *mattk; { register int tmp; register int dam = d((int)mattk->damn, (int)mattk->damd); /* Not totally the same as for real monsters. Specifically, these * don't take multiple moves. (It's just too hard, for too little * result, to program monsters which attack from inside you, which * would be necessary if done accurately.) Instead, we arbitrarily * kill the monster immediately for AD_DGST and we regurgitate them * after exactly 1 round of attack otherwise. -KAA */ if(mdef->data->msize >= MZ_HUGE) return 0; if(u.uhunger < 1500 && !u.uswallow) { if(mdef->data->mlet != S_COCKATRICE) { # ifdef LINT /* static char msgbuf[BUFSZ]; */ char msgbuf[BUFSZ]; # else static char msgbuf[BUFSZ]; # endif /* TODO: get the symbol display also to work (monster symbol is removed from * the screen and you moved onto it, then you get moved back and it gets * moved back if the monster survives--just like when monsters swallow you. */ kludge("You engulf %s!", mon_nam(mdef)); switch(mattk->adtyp) { case AD_DGST: u.uhunger += mdef->data->cnutrit; newuhs(FALSE); xkilled(mdef,2); Sprintf(msgbuf, "You totally digest %s.", Blind ? "it" : mon_nam(mdef)); if (tmp = 3 + (mdef->data->cwt >> 2)) { kludge("You digest %s.", mon_nam(mdef)); nomul(-tmp); nomovemsg = msgbuf; } else pline(msgbuf); return(2); case AD_PHYS: kludge("%s is pummeled with your debris!",Monnam(mdef)); break; case AD_ACID: kludge("%s is covered with your goo!", Monnam(mdef)); if (resists_acid(mdef->data)) { kludge("It seems harmless to %s.", mon_nam(mdef)); dam = 0; } break; case AD_BLND: if (mdef->mcansee) kludge("%s can't see in there!", Monnam(mdef)); mdef->mcansee = 0; dam += mdef->mblinded; if (dam > 127) dam = 127; mdef->mblinded = dam; dam = 0; break; case AD_ELEC: if (rn2(2)) { kludge("The air around %s crackles with electricity.", mon_nam(mdef)); if (resists_elec(mdef->data)) { kludge("%s seems unhurt.", Monnam(mdef)); dam = 0; } # ifdef GOLEMS golemeffects(mdef,(int)mattk->adtyp,dam); # endif } else dam = 0; break; case AD_COLD: if (rn2(2)) { if (resists_cold(mdef->data)) { kludge("%s seems mildly chilly.", Monnam(mdef)); dam = 0; } else kludge("%s is freezing to death!",Monnam(mdef)); # ifdef GOLEMS golemeffects(mdef,(int)mattk->adtyp,dam); # endif } else dam = 0; break; case AD_FIRE: if (rn2(2)) { if (resists_fire(mdef->data)) { kludge("%s seems mildly hot.", Monnam(mdef)); dam = 0; } else kludge("%s is burning to a crisp!",Monnam(mdef)); # ifdef GOLEMS golemeffects(mdef,(int)mattk->adtyp,dam); # endif } else dam = 0; break; } if ((mdef->mhp -= dam) <= 0) { kludge("%s is killed!", Monnam(mdef)); xkilled(mdef,0); return(2); } kludge("You %s %s!", is_animal(uasmon) ? "regurgitate" : "expel", mon_nam(mdef)); if (is_animal(uasmon)) { if (Blind) pline("Obviously, you didn't like its taste."); else pline("Obviously, you didn't like %s's taste.", mon_nam(mdef)); } } else { kludge("You bite into %s", mon_nam(mdef)); You("turn to stone..."); killer_format = KILLED_BY; killer = "swallowing a cockatrice whole"; done(STONING); } } return(0); } void missum(mdef,mattk) register struct monst *mdef; register struct attack *mattk; { if (could_seduce(&youmonst, mdef, mattk)) kludge("You pretend to be friendly to %s.", mon_nam(mdef)); else if(!Blind && flags.verbose) You("miss %s.", mon_nam(mdef)); else You("miss it."); wakeup(mdef); } static boolean hmonas(mon, tmp) /* attack monster as a monster. */ register struct monst *mon; register int tmp; { register struct attack *mattk; int i, sum[NATTK]; int nsum = 0; schar dhit; for(i = 0; i < NATTK; i++) { sum[i] = 0; mattk = &(uasmon->mattk[i]); switch(mattk->aatyp) { case AT_WEAP: use_weapon: /* Certain monsters don't use weapons when encountered as enemies, * but players who polymorph into them have hands or claws and thus * should be able to use weapons. This shouldn't prohibit the use * of most special abilities, either. */ /* Potential problem: if the monster gets multiple weapon attacks, * we currently allow the player to get each of these as a weapon * attack. Is this really desirable? */ if(uwep) tmp += hitval(uwep, mon->data); dhit = (tmp > rnd(20) || u.uswallow); /* Enemy dead, before any special abilities used */ if (!known_hitum(mon,dhit)) return 0; /* Do not print "You hit" message, since known_hitum * already did it. */ if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS) sum[i] = damageum(mon,mattk); break; case AT_CLAW: if (i==0 && uwep && !cantwield(uasmon)) goto use_weapon; # ifdef SEDUCE /* succubi/incubi are humanoid, but their _second_ * attack is AT_CLAW, not their first... */ if (i==1 && uwep && (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS)) goto use_weapon; # endif case AT_KICK: case AT_BITE: case AT_STNG: case AT_TUCH: case AT_BUTT: if (i==0 && uwep && (u.usym==S_LICH)) goto use_weapon; if(dhit = (tmp > rnd(20) || u.uswallow)) { int compat; if (!u.uswallow && (compat = could_seduce(&youmonst, mon, mattk))) You("%s %s %s.", mon->mcansee ? "smile at" : "talk to", Blind ? "it" : mon_nam(mon), compat == 2 ? "engagingly" : "seductively"); else if (mattk->aatyp == AT_KICK) kludge("You kick %s.", mon_nam(mon)); else if (mattk->aatyp == AT_BITE) kludge("You bite %s.", mon_nam(mon)); else if (mattk->aatyp == AT_STNG) kludge("You sting %s.", mon_nam(mon)); else if (mattk->aatyp == AT_BUTT) kludge("You butt %s.", mon_nam(mon)); else if (mattk->aatyp == AT_TUCH) kludge("You touch %s.", mon_nam(mon)); else kludge("You hit %s.", mon_nam(mon)); sum[i] = damageum(mon, mattk); } else missum(mon, mattk); break; case AT_HUGS: /* automatic if prev two attacks succeed, or if * already grabbed in a previous attack */ dhit = 1; if (!sticks(mon->data)) if (mon==u.ustuck) { kludge("%s is being %s.", Monnam(mon), # ifdef GOLEMS u.umonnum==PM_ROPE_GOLEM ? "choked": # endif "crushed"); sum[i] = damageum(mon, mattk); } else if(sum[i-1] && sum[i-2]) { kludge("You grab %s!", mon_nam(mon)); u.ustuck = mon; sum[i] = damageum(mon, mattk); } break; case AT_EXPL: /* automatic hit if next to */ dhit = -1; sum[i] = explum(mon, mattk); break; case AT_ENGL: if((dhit = (tmp > rnd(20+i)))) sum[i]= gulpum(mon,mattk); else missum(mon, mattk); break; case AT_MAGC: /* No check for uwep; if wielding nothing we want to * do the normal 1-2 points bare hand damage... */ if (i==0 && (u.usym==S_KOBOLD || u.usym==S_ORC || u.usym==S_GNOME )) goto use_weapon; case AT_NONE: continue; /* Not break--avoid passive attacks from enemy */ default: /* Strange... */ impossible("strange attack of yours (%d)", mattk->aatyp); case AT_BREA: case AT_SPIT: case AT_GAZE: /* all done using #monster command */ dhit = 0; break; } if (dhit == -1) rehumanize(); if(sum[i] == 2) return(passive(mon, 1, 0, (mattk->aatyp==AT_KICK))); /* defender dead */ else { (void) passive(mon, sum[i], 1, (mattk->aatyp==AT_KICK)); nsum |= sum[i]; } if (uasmon == &playermon) break; /* No extra attacks if no longer a monster */ if (multi < 0) break; /* If paralyzed while attacking, i.e. floating eye */ } return(nsum); } #endif /* POLYSELF */ /* Special (passive) attacks on you by monsters done here. */ int passive(mon, mhit, malive, kicked) register struct monst *mon; register boolean mhit; register int malive; boolean kicked; { register struct permonst *ptr = mon->data; register int i, tmp; for(i = 0; ; i++) { if(i >= NATTK) return(malive | mhit); /* no passive attacks */ if(ptr->mattk[i].aatyp == AT_NONE) break; /* try this one */ } /* These affect you even if they just died */ switch(ptr->mattk[i].adtyp) { case AD_ACID: if(mhit && rn2(2)) { if (Blind || !flags.verbose) You("are splashed!"); else You("are splashed by %s's acid!", mon_nam(mon)); tmp = d((int)mon->m_lev, (int)ptr->mattk[i].damd); #ifdef POLYSELF if(!resists_acid(uasmon)) #endif mdamageu(mon, tmp); if(!rn2(30)) corrode_armor(); } if(mhit && !rn2(6)) { if (kicked) { if (uarmf) (void) rust_dmg(uarmf, xname(uarmf), 3, TRUE); } else corrode_weapon(); } break; case AD_STON: if(mhit) if (!kicked) if (!uwep && !uarmg #ifdef POLYSELF && !resists_ston(uasmon) #endif ) { You("turn to stone..."); done_in_by(mon); return 2; } break; case AD_RUST: if(mhit) if (kicked) { if (uarmf) (void) rust_dmg(uarmf, xname(uarmf), 1, TRUE); } else corrode_weapon(); break; case AD_MAGM: /* wrath of gods for attacking Oracle */ if(Antimagic) { shieldeff(u.ux, u.uy); pline("A hail of magic missiles narrowly misses you!"); } else { tmp = d((int)mon->m_lev+1, (int)ptr->mattk[i].damd); You("are hit by magic missiles appearing from thin air!"); mdamageu(mon, tmp); } break; default: break; } /* These only affect you if they still live */ if(malive && !mon->mcan && rn2(3)) { switch(ptr->mattk[i].adtyp) { case AD_PLYS: tmp = -d((int)mon->m_lev+1, (int)ptr->mattk[i].damd); if(ptr == &mons[PM_FLOATING_EYE]) { if (!canseemon(mon)) { tmp = 0; break; } if(mon->mcansee) { if(Reflecting & W_AMUL) { makeknown(AMULET_OF_REFLECTION); pline("%s's gaze is reflected by your medallion.", Monnam(mon)); } else if(Reflecting & W_ARMS) { makeknown(SHIELD_OF_REFLECTION); pline("%s's gaze is reflected by your shield.", Monnam(mon)); } else { You("are frozen by %s's gaze!", mon_nam(mon)); nomul((ACURR(A_WIS) > 12 || rn2(4)) ? tmp : -120); } } else { pline("%s cannot defend itself.", Amonnam(mon,"blind")); if(!rn2(500)) change_luck(-1); } } else { /* gelatinous cube */ You("are frozen by %s!", mon_nam(mon)); nomul(tmp); tmp = 0; } break; case AD_COLD: /* brown mold or blue jelly */ if(monnear(mon, u.ux, u.uy)) { tmp = d((int)mon->m_lev+1, (int)ptr->mattk[i].damd); if(Cold_resistance) { shieldeff(u.ux, u.uy); You("feel a mild chill."); #ifdef POLYSELF #ifdef GOLEMS ugolemeffects(AD_COLD, tmp); #endif /* GOLEMS */ #endif tmp = 0; break; } You("are suddenly very cold!"); mdamageu(mon, tmp); /* monster gets stronger with your heat! */ mon->mhp += tmp / 2; if (mon->mhpmax < mon->mhp) mon->mhpmax = mon->mhp; /* at a certain point, the monster will reproduce! */ if(mon->mhpmax > ((mon->m_lev+1) * 8)) { register struct monst *mtmp; if(mtmp = clone_mon(mon)) { mtmp->mhpmax = mon->mhpmax /= 2; if(!Blind) pline("%s multiplies from your heat!", Monnam(mon)); } } } break; case AD_STUN: /* specifically yellow mold */ if(!Stunned) make_stunned((long)d((int)mon->m_lev+1, (int)ptr->mattk[i].damd), TRUE); break; case AD_FIRE: if(monnear(mon, u.ux, u.uy)) { tmp = d((int)mon->m_lev+1, (int)ptr->mattk[i].damd); if(Fire_resistance) { shieldeff(u.ux, u.uy); You("feel mildly warm."); #if defined(POLYSELF) && defined(GOLEMS) ugolemeffects(AD_FIRE, tmp); #endif tmp = 0; break; } You("are suddenly very hot!"); mdamageu(mon, tmp); } break; case AD_ELEC: tmp = d((int)mon->m_lev+1, (int)ptr->mattk[i].damd); if(Shock_resistance) { shieldeff(u.ux, u.uy); You("feel a mild tingle."); #if defined(POLYSELF) && defined(GOLEMS) ugolemeffects(AD_ELEC, tmp); #endif tmp = 0; break; } You("are jolted with electricity!"); mdamageu(mon, tmp); break; default: break; } } return(malive | mhit); } /* Note: caller must ascertain mtmp->mimic... */ void stumble_onto_mimic(mtmp) register struct monst *mtmp; { if(!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data,AD_STCK)) u.ustuck = mtmp; if (Blind) goto generic; else if (levl[u.ux+u.dx][u.uy+u.dy].scrsym == CLOSED_DOOR_SYM) #ifdef SPELLS { if (IS_ROCK(levl[u.ux+u.dx][u.uy+u.dy].typ) || IS_DOOR(levl[u.ux+u.dx][u.uy+u.dy].typ)) #endif pline("The door actually was %s.", defmonnam(mtmp)); #ifdef SPELLS else pline("That spellbook was %s.", defmonnam(mtmp)); } #endif else if (levl[u.ux+u.dx][u.uy+u.dy].scrsym == GOLD_SYM) pline("That gold was %s!", defmonnam(mtmp)); else { generic: pline("Wait! That's %s!", defmonnam(mtmp)); } wakeup(mtmp); /* clears mtmp->mimic */ } static void nohandglow() { if (!u.umconf) return; /* for safety */ if (u.umconf == 1) { if (Blind) Your("%s stop tingling.", makeplural(body_part(HAND))); else Your("%s stop glowing %s.", makeplural(body_part(HAND)), Hallucination ? hcolor() : red); } else { if (Blind) pline("The tingling in your %s lessens.", makeplural(body_part(HAND))); else Your("%s no longer glow so brightly %s.", makeplural(body_part(HAND)), Hallucination ? hcolor() : red); } u.umconf--; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.