void losestr(int num, int how, const char *killer, struct monst *magr) { /* may kill you; cause may be poison or monster like 'a' */ int ustr = ABASE(A_STR) - num; while (ustr < 3) { ++ustr; --num; if (Upolyd) { u.mh -= 6; u.mhmax -= 6; if (u.mh <= 0) { if (how == STARVING) pline("You can't go on any more like this."); rehumanize(how, killer); } } else { u.uhp -= 6; u.uhpmax -= 6; if (u.uhp <= 0) { if (how == STARVING) pline("You die from hunger and exhaustion."); if (magr) /* don't give at the same time as STARVING */ done_in_by(magr, killer); else done(how, killer); } } } adjattrib(A_STR, -num, TRUE); }
void youswld(struct monst *mtmp, int dam, int die, char *name) { if(mtmp != u.ustuck) { return; } kludge("%s digests you!", name); u.uhp -= dam; if(u.uswldtim == die) { ++u.uswldtim; pline("It totally digests you!"); u.uhp = -1; } ++u.uswldtim; if(u.uhp < 1) { done_in_by(mtmp); } }
void inrange(struct monst *mtmp) { schar tx; schar 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 == 0) && (abs(ty) < 8)) || ((ty == 0) && (abs(tx) < 8)) || ((abs(tx) == abs(ty)) && (abs(tx) < 8))) { /* Spit fire in the direction of @ (not necessarily hitting) */ buzz(-1, mtmp->mx, mtmp->my, sgn(tx), sgn(ty)); if(u.uhp < 1) { done_in_by(mtmp); } } }
void inrange(struct monst *mtmp) { schar tx,ty; /* do nothing if cancelled (but make '1' say something) */ if(mtmp->data->mlet != '1' && mtmp->mcan) return; /* 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) < BOLT_LIM) || (!ty && abs(tx) < BOLT_LIM) || (abs(tx) == abs(ty) && abs(tx) < BOLT_LIM)){ switch(mtmp->data->mlet) { case 'D': /* spit fire in the direction of @ (not nec. hitting) */ buzz(-1,mtmp->mx,mtmp->my,sgn(tx),sgn(ty)); break; case '1': if(rn2(WIZSHOT)) break; /* if you zapped wizard with wand of cancellation, he has to shake off the effects before he can throw spells successfully. 1/2 the time they fail anyway */ if(mtmp->mcan || rn2(2)) { if(canseemon(mtmp)) pline("%s makes a gesture, then curses.", Monnam(mtmp)); else pline("You hear mumbled cursing."); if(!rn2(3)) { mtmp->mspeed = 0; mtmp->minvis = 0; } if(!rn2(3)) mtmp->mcan = 0; } else { if(canseemon(mtmp)){ if(!rn2(6) && !Invis) { pline("%s hypnotizes you.", Monnam(mtmp)); nomul(rn2(3) + 3); break; } else pline("%s chants an incantation.", Monnam(mtmp)); } else pline("You hear a mumbled incantation."); switch(rn2(Invis ? 5 : 6)) { case 0: /* create a nasty monster from a deep level */ /* (for the moment, 'nasty' is not implemented) */ (void) makemon((struct permonst *)0, u.ux, u.uy); break; case 1: pline("\"Destroy the thief, my pets!\""); aggravate(); /* aggravate all the monsters */ /* fall into next case */ case 2: if (flags.no_of_wizards == 1 && rnd(5) == 0) /* if only 1 wizard, clone himself */ clonewiz(mtmp); break; case 3: if(mtmp->mspeed == MSLOW) mtmp->mspeed = 0; else mtmp->mspeed = MFAST; break; case 4: mtmp->minvis = 1; break; case 5: /* Only if not Invisible */ pline("You hear a clap of thunder!"); /* shoot a bolt of fire or cold, or a sleep ray */ buzz(-rnd(3),mtmp->mx,mtmp->my,sgn(tx),sgn(ty)); break; } } } if(u.uhp < 1) done_in_by(mtmp); } }
/* return TRUE if mon still alive */ bool hmon(struct monst *mon, struct obj *obj, int thrown) { int tmp; bool hittxt = FALSE; if (!obj) { tmp = rnd(2); /* attack with bare hands */ if (mon->data->mlet == 'c' && !uarmg) { pline("You hit the cockatrice with your bare hands."); pline("You turn to stone ..."); done_in_by(mon); } } else if (obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE) { if (obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG)) tmp = rnd(2); else { if (strchr(mlarge, mon->data->mlet)) { tmp = rnd(objects[obj->otyp].wldam); if (obj->otyp == TWO_HANDED_SWORD) tmp += d(2, 6); else if (obj->otyp == FLAIL) tmp += rnd(4); } else tmp = rnd(objects[obj->otyp].wsdam); tmp += obj->spe; if (!thrown && obj == uwep && obj->otyp == BOOMERANG && !rn2(3)) { pline("As you hit %s, the boomerang breaks into splinters.", monnam(mon)); freeinv(obj); setworn(NULL, obj->owornmask); obfree(obj, NULL); tmp++; } } if (mon->data->mlet == 'O' && obj->otyp == TWO_HANDED_SWORD && !strcmp(ONAME(obj), "Orcrist")) tmp += rnd(10); } else switch (obj->otyp) { case HEAVY_IRON_BALL: tmp = rnd(25); break; case EXPENSIVE_CAMERA: pline("You succeed in destroying your camera. Congratulations!"); freeinv(obj); if (obj->owornmask) setworn(NULL, obj->owornmask); obfree(obj, NULL); return (TRUE); case DEAD_COCKATRICE: pline("You hit %s with the cockatrice corpse.", monnam(mon)); if (mon->data->mlet == 'c') { tmp = 1; hittxt = TRUE; break; } pline("%s is turned to stone!", Monnam(mon)); killed(mon); return (FALSE); case CLOVE_OF_GARLIC: /* no effect against demons */ if (strchr(UNDEAD, mon->data->mlet)) mon->mflee = 1; tmp = 1; break; 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) */ tmp += u.udaminc + dbon(); if (u.uswallow) { if ((tmp -= u.uswldtim) <= 0) { pline("Your arms are no longer able to hit."); return (TRUE); } } if (tmp < 1) tmp = 1; mon->mhp -= tmp; if (mon->mhp < 1) { killed(mon); return (FALSE); } if (mon->mtame && (!mon->mflee || mon->mfleetim)) { mon->mflee = 1; /* Rick Richardson */ mon->mfleetim += 10 * rnd(tmp); } if (!hittxt) { if (thrown) { /* this assumes that we cannot throw plural things */ hit(xname(obj) /* or: objects[obj->otyp].oc_name */, mon, exclam(tmp)); } else if (Blind) pline("You hit it."); else pline("You hit %s%s", monnam(mon), exclam(tmp)); } if (u.umconf && !thrown) { if (!Blind) { pline("Your hands stop glowing blue."); if (!mon->mfroz && !mon->msleep) pline("%s appears confused.", Monnam(mon)); } mon->mconf = 1; u.umconf = 0; } return (TRUE); /* mon still alive */ }
/* If dmg is zero, then the monster is not casting at you. If the monster is intentionally not casting at you, we have previously called spell_would_be_useless() and spellnum should always be a valid undirected spell. If you modify either of these, be sure to change is_undirected_spell() and spell_would_be_useless(). */ static void cast_wizard_spell(struct monst *mtmp, int dmg, int spellnum) { if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) { impossible("cast directed wizard spell (%d) with dmg=0?", spellnum); return; } switch (spellnum) { case MGC_DEATH_TOUCH: pline("Oh no, %s's using the touch of death!", mhe(mtmp)); if (nonliving(youmonst.data) || is_demon(youmonst.data)) { pline("You seem no deader than before."); } else if (!Antimagic && rn2(mtmp->m_lev) > 12) { if (Hallucination) { pline("You have an out of body experience."); } else { killer_format = KILLED_BY_AN; killer = "touch of death"; done(DIED); } } else { if (Antimagic) shieldeff(u.ux, u.uy); pline("Lucky for you, it didn't work!"); } dmg = 0; break; case MGC_CLONE_WIZ: if (mtmp->iswiz && flags.no_of_wizards == 1) { pline("Double Trouble..."); clonewiz(); dmg = 0; } else impossible("bad wizard cloning?"); break; case MGC_SUMMON_MONS: { int count; count = nasty(mtmp); /* summon something nasty */ if (mtmp->iswiz) verbalize("Destroy the thief, my pet%s!", plur(count)); else { const char *mappear = (count == 1) ? "A monster appears" : "Monsters appear"; /* messages not quite right if plural monsters created but only a single monster is seen */ if (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around a spot near you!", mappear); else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around your displaced image!", mappear); else pline("%s from nowhere!", mappear); } dmg = 0; break; } case MGC_AGGRAVATION: pline("You feel that monsters are aware of your presence."); aggravate(); dmg = 0; break; case MGC_CURSE_ITEMS: pline("You feel as if you need some help."); rndcurse(); dmg = 0; break; case MGC_DESTRY_ARMR: if (Antimagic) { shieldeff(u.ux, u.uy); pline("A field of force surrounds you!"); } else if (!destroy_arm(some_armor(&youmonst))) { pline("Your skin itches."); } dmg = 0; break; case MGC_WEAKEN_YOU: /* drain strength */ if (Antimagic) { shieldeff(u.ux, u.uy); pline("You feel momentarily weakened."); } else { pline("You suddenly feel weaker!"); dmg = mtmp->m_lev - 6; if (Half_spell_damage) dmg = (dmg + 1) / 2; losestr(rnd(dmg)); if (u.uhp < 1) done_in_by(mtmp); } dmg = 0; break; case MGC_DISAPPEAR: /* makes self invisible */ if (!mtmp->minvis && !mtmp->invis_blkd) { if (canseemon(mtmp)) pline("%s suddenly %s!", Monnam(mtmp), !See_invisible ? "disappears" : "becomes transparent"); mon_set_minvis(mtmp); dmg = 0; } else impossible("no reason for monster to cast disappear spell?"); break; case MGC_STUN_YOU: if (Antimagic || Free_action) { shieldeff(u.ux, u.uy); if (!Stunned) pline("You feel momentarily disoriented."); make_stunned(1L, FALSE); } else { pline(Stunned ? "You struggle to keep your balance." : "You reel..."); dmg = dice(ACURR(A_DEX) < 12 ? 6 : 4, 4); if (Half_spell_damage) dmg = (dmg + 1) / 2; make_stunned(HStun + dmg, FALSE); } dmg = 0; break; case MGC_HASTE_SELF: mon_adjust_speed(mtmp, 1, NULL); dmg = 0; break; case MGC_CURE_SELF: if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) pline("%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += dice(3,6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; dmg = 0; } break; case MGC_PSI_BOLT: /* prior to 3.4.0 Antimagic was setting the damage to 1--this made the spell virtually harmless to players with magic res. */ if (Antimagic) { shieldeff(u.ux, u.uy); dmg = (dmg + 1) / 2; } if (dmg <= 5) pline("You get a slight %sache.", body_part(HEAD)); else if (dmg <= 10) pline("Your brain is on fire!"); else if (dmg <= 20) pline("Your %s suddenly aches painfully!", body_part(HEAD)); else pline("Your %s suddenly aches very painfully!", body_part(HEAD)); break; default: impossible("mcastu: invalid magic spell (%d)", spellnum); dmg = 0; break; } if (dmg) mdamageu(mtmp, dmg); }
/* * mhitu: monster hits you * returns 1 if monster dies (e.g. 'y', 'F'), 0 otherwise */ bool mhitu(struct monst *mtmp) { struct permonst *mdat = mtmp->data; int tmp, ctmp; nomul(0); /* If swallowed, can only be affected by hissers and by u.ustuck */ if (u.uswallow) { if (mtmp != u.ustuck) { if (mdat->mlet == 'c' && !rn2(13)) { pline("Outside, you hear %s's hissing!", monnam(mtmp)); pline("%s gets turned to stone!", Monnam(u.ustuck)); pline("And the same fate befalls you."); done_in_by(mtmp); /* "notreached": not return(1); */ } return (0); } switch (mdat->mlet) { /* now mtmp == u.ustuck */ case ',': youswld(mtmp, (u.uac > 0) ? u.uac + 4 : 4, 5, "The trapper"); break; case '\'': youswld(mtmp, rnd(6), 7, "The lurker above"); break; case 'P': youswld(mtmp, d(2, 4), 12, "The purple worm"); break; default: /* This is not impossible! */ pline("The mysterious monster totally digests you."); u.uhp = 0; } if (u.uhp < 1) done_in_by(mtmp); return (0); } if (mdat->mlet == 'c' && Stoned) return (0); /* make eels visible the moment they hit/miss us */ if (mdat->mlet == ';' && mtmp->minvis && cansee(mtmp->mx, mtmp->my)) { mtmp->minvis = 0; pmon(mtmp); } if (!strchr("1&DuxynNF", mdat->mlet)) tmp = hitu(mtmp, d(mdat->damn, mdat->damd)); else tmp = 0; if (strchr(UNDEAD, mdat->mlet) && midnight()) tmp += hitu(mtmp, d(mdat->damn, mdat->damd)); ctmp = tmp && !mtmp->mcan && (!uarm || objects[uarm->otyp].a_can < rnd(3) || !rn2(50)); switch (mdat->mlet) { case '1': if (wiz_hit(mtmp)) /* he disappeared */ return (1); break; case '&': if (!mtmp->cham && !mtmp->mcan && !rn2(13)) { makemon(PM_DEMON, u.ux, u.uy); } else { hitu(mtmp, d(2, 6)); hitu(mtmp, d(2, 6)); hitu(mtmp, rnd(3)); hitu(mtmp, rnd(3)); hitu(mtmp, rn1(4, 2)); } break; case ',': if (tmp) justswld(mtmp, "The trapper"); break; case '\'': if (tmp) justswld(mtmp, "The lurker above"); break; case ';': if (ctmp) { if (!u.ustuck && !rn2(10)) { pline("%s swings itself around you!", Monnam(mtmp)); u.ustuck = mtmp; } else if (u.ustuck == mtmp && levl[mtmp->mx][mtmp->my].typ == POOL) { pline("%s drowns you ...", Monnam(mtmp)); done("drowned"); } } break; case 'A': if (ctmp && rn2(2)) { if (Poison_resistance) pline("The sting doesn't seem to affect you."); else { pline("You feel weaker!"); losestr(1); } } break; case 'C': hitu(mtmp, rnd(6)); break; case 'c': if (!rn2(5)) { pline("You hear %s's hissing!", monnam(mtmp)); if (ctmp || !rn2(20) || (flags.moonphase == NEW_MOON && !carrying(DEAD_LIZARD))) Stoned = 5; } break; case 'D': if (rn2(6) || mtmp->mcan) { hitu(mtmp, d(3, 10)); hitu(mtmp, rnd(8)); 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': hitu(mtmp, d(2, (flags.moonphase == FULL_MOON) ? 3 : 4)); break; case 'e': 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(3)) { 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) { hitu(mtmp, rnd(4)); 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 { hitu(mtmp, d(2, 6)); hitu(mtmp, d(2, 6)); } break; case 'o': tmp = hitu(mtmp, rnd(6)); if (hitu(mtmp, rnd(6)) && tmp && /* hits with both paws */ !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 (ctmp && !rn2(4)) justswld(mtmp, "The purple worm"); else hitu(mtmp, d(2, 4)); break; case 'Q': hitu(mtmp, rnd(2)); 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 && !uarm->rustfree && /* Mike Newton */ 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); hitu(mtmp, rnd(8)); hitu(mtmp, rnd(8)); break; case 'T': hitu(mtmp, rnd(6)); hitu(mtmp, rnd(6)); break; case 't': if (!rn2(5)) rloc(mtmp); break; case 'u': mtmp->mflee = 1; break; case 'U': hitu(mtmp, d(3, 4)); 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) losexp(); break; case 'W': if (ctmp) losexp(); break; #ifndef NOWORM case 'w': if (tmp) wormhit(mtmp); #endif /* NOWORM */ break; case 'X': hitu(mtmp, rnd(5)); hitu(mtmp, rnd(5)); hitu(mtmp, rnd(5)); break; case 'x': { long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE; pline("%s pricks in your %s leg!", Monnam(mtmp), (side == RIGHT_SIDE) ? "right" : "left"); set_wounded_legs(side, rnd(50)); 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': hitu(mtmp, rnd(6)); break; } if (u.uhp < 1) done_in_by(mtmp); return (0); }