1 /* $NetBSD: hack.fight.c,v 1.6 2003/04/02 18:36:36 jsm Exp $ */ 2 3 /* 4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 * Amsterdam 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are 10 * met: 11 * 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * - Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * - Neither the name of the Stichting Centrum voor Wiskunde en 20 * Informatica, nor the names of its contributors may be used to endorse or 21 * promote products derived from this software without specific prior 22 * written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. The name of the author may not be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 #include <sys/cdefs.h> 65 #ifndef lint 66 __RCSID("$NetBSD: hack.fight.c,v 1.6 2003/04/02 18:36:36 jsm Exp $"); 67 #endif /* not lint */ 68 69 #include "hack.h" 70 #include "extern.h" 71 72 static boolean far_noise; 73 static long noisetime; 74 75 /* hitmm returns 0 (miss), 1 (hit), or 2 (kill) */ 76 int 77 hitmm(magr, mdef) 78 struct monst *magr, *mdef; 79 { 80 const struct permonst *pa = magr->data, *pd = mdef->data; 81 int hit; 82 schar tmp; 83 boolean vis; 84 if (strchr("Eauy", pa->mlet)) 85 return (0); 86 if (magr->mfroz) 87 return (0); /* riv05!a3 */ 88 tmp = pd->ac + pa->mlevel; 89 if (mdef->mconf || mdef->mfroz || mdef->msleep) { 90 tmp += 4; 91 if (mdef->msleep) 92 mdef->msleep = 0; 93 } 94 hit = (tmp > rnd(20)); 95 if (hit) 96 mdef->msleep = 0; 97 vis = (cansee(magr->mx, magr->my) && cansee(mdef->mx, mdef->my)); 98 if (vis) { 99 char buf[BUFSZ]; 100 if (mdef->mimic) 101 seemimic(mdef); 102 if (magr->mimic) 103 seemimic(magr); 104 (void) sprintf(buf, "%s %s", Monnam(magr), 105 hit ? "hits" : "misses"); 106 pline("%s %s.", buf, monnam(mdef)); 107 } else { 108 boolean far = (dist(magr->mx, magr->my) > 15); 109 if (far != far_noise || moves - noisetime > 10) { 110 far_noise = far; 111 noisetime = moves; 112 pline("You hear some noises%s.", 113 far ? " in the distance" : ""); 114 } 115 } 116 if (hit) { 117 if (magr->data->mlet == 'c' && !magr->cham) { 118 magr->mhpmax += 3; 119 if (vis) 120 pline("%s is turned to stone!", Monnam(mdef)); 121 else if (mdef->mtame) 122 pline("You have a peculiarly sad feeling for a moment, then it passes."); 123 monstone(mdef); 124 hit = 2; 125 } else if ((mdef->mhp -= d(pa->damn, pa->damd)) < 1) { 126 magr->mhpmax += 1 + rn2(pd->mlevel + 1); 127 if (magr->mtame && magr->mhpmax > 8 * pa->mlevel) { 128 if (pa == &li_dog) 129 magr->data = pa = &dog; 130 else if (pa == &dog) 131 magr->data = pa = &la_dog; 132 } 133 if (vis) 134 pline("%s is killed!", Monnam(mdef)); 135 else if (mdef->mtame) 136 pline("You have a sad feeling for a moment, then it passes."); 137 mondied(mdef); 138 hit = 2; 139 } 140 } 141 return (hit); 142 } 143 144 /* drop (perhaps) a cadaver and remove monster */ 145 void 146 mondied(mdef) 147 struct monst *mdef; 148 { 149 const struct permonst *pd = mdef->data; 150 if (letter(pd->mlet) && rn2(3)) { 151 (void) mkobj_at(pd->mlet, mdef->mx, mdef->my); 152 if (cansee(mdef->mx, mdef->my)) { 153 unpmon(mdef); 154 atl(mdef->mx, mdef->my, fobj->olet); 155 } 156 stackobj(fobj); 157 } 158 mondead(mdef); 159 } 160 161 /* drop a rock and remove monster */ 162 void 163 monstone(mdef) 164 struct monst *mdef; 165 { 166 if (strchr(mlarge, mdef->data->mlet)) 167 mksobj_at(ENORMOUS_ROCK, mdef->mx, mdef->my); 168 else 169 mksobj_at(ROCK, mdef->mx, mdef->my); 170 if (cansee(mdef->mx, mdef->my)) { 171 unpmon(mdef); 172 atl(mdef->mx, mdef->my, fobj->olet); 173 } 174 mondead(mdef); 175 } 176 177 178 int 179 fightm(mtmp) 180 struct monst *mtmp; 181 { 182 struct monst *mon; 183 for (mon = fmon; mon; mon = mon->nmon) 184 if (mon != mtmp) { 185 if (DIST(mon->mx, mon->my, mtmp->mx, mtmp->my) < 3) 186 if (rn2(4)) 187 return (hitmm(mtmp, mon)); 188 } 189 return (-1); 190 } 191 192 /* u is hit by sth, but not a monster */ 193 int 194 thitu(tlev, dam, name) 195 int tlev, dam; 196 const char *name; 197 { 198 char buf[BUFSZ]; 199 setan(name, buf); 200 if (u.uac + tlev <= rnd(20)) { 201 if (Blind) 202 pline("It misses."); 203 else 204 pline("You are almost hit by %s!", buf); 205 return (0); 206 } else { 207 if (Blind) 208 pline("You are hit!"); 209 else 210 pline("You are hit by %s!", buf); 211 losehp(dam, name); 212 return (1); 213 } 214 } 215 216 char mlarge[] = "bCDdegIlmnoPSsTUwY',&"; 217 218 boolean 219 hmon(mon, obj, thrown) /* return TRUE if mon still alive */ 220 struct monst *mon; 221 struct obj *obj; 222 int thrown; 223 { 224 int tmp; 225 boolean hittxt = FALSE; 226 227 if (!obj) { 228 tmp = rnd(2); /* attack with bare hands */ 229 if (mon->data->mlet == 'c' && !uarmg) { 230 pline("You hit the cockatrice with your bare hands."); 231 pline("You turn to stone ..."); 232 done_in_by(mon); 233 } 234 } else if (obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE) { 235 if (obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG)) 236 tmp = rnd(2); 237 else { 238 if (strchr(mlarge, mon->data->mlet)) { 239 tmp = rnd(objects[obj->otyp].wldam); 240 if (obj->otyp == TWO_HANDED_SWORD) 241 tmp += d(2, 6); 242 else if (obj->otyp == FLAIL) 243 tmp += rnd(4); 244 } else { 245 tmp = rnd(objects[obj->otyp].wsdam); 246 } 247 tmp += obj->spe; 248 if (!thrown && obj == uwep && obj->otyp == BOOMERANG 249 && !rn2(3)) { 250 pline("As you hit %s, the boomerang breaks into splinters.", 251 monnam(mon)); 252 freeinv(obj); 253 setworn((struct obj *) 0, obj->owornmask); 254 obfree(obj, (struct obj *) 0); 255 tmp++; 256 } 257 } 258 if (mon->data->mlet == 'O' && obj->otyp == TWO_HANDED_SWORD && 259 !strcmp(ONAME(obj), "Orcrist")) 260 tmp += rnd(10); 261 } else 262 switch (obj->otyp) { 263 case HEAVY_IRON_BALL: 264 tmp = rnd(25); 265 break; 266 case EXPENSIVE_CAMERA: 267 pline("You succeed in destroying your camera. Congratulations!"); 268 freeinv(obj); 269 if (obj->owornmask) 270 setworn((struct obj *) 0, obj->owornmask); 271 obfree(obj, (struct obj *) 0); 272 return (TRUE); 273 case DEAD_COCKATRICE: 274 pline("You hit %s with the cockatrice corpse.", 275 monnam(mon)); 276 if (mon->data->mlet == 'c') { 277 tmp = 1; 278 hittxt = TRUE; 279 break; 280 } 281 pline("%s is turned to stone!", Monnam(mon)); 282 killed(mon); 283 return (FALSE); 284 case CLOVE_OF_GARLIC: /* no effect against demons */ 285 if (strchr(UNDEAD, mon->data->mlet)) 286 mon->mflee = 1; 287 tmp = 1; 288 break; 289 default: 290 /* non-weapons can damage because of their weight */ 291 /* (but not too much) */ 292 tmp = obj->owt / 10; 293 if (tmp < 1) 294 tmp = 1; 295 else 296 tmp = rnd(tmp); 297 if (tmp > 6) 298 tmp = 6; 299 } 300 301 /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) */ 302 303 tmp += u.udaminc + dbon(); 304 if (u.uswallow) { 305 if ((tmp -= u.uswldtim) <= 0) { 306 pline("Your arms are no longer able to hit."); 307 return (TRUE); 308 } 309 } 310 if (tmp < 1) 311 tmp = 1; 312 mon->mhp -= tmp; 313 if (mon->mhp < 1) { 314 killed(mon); 315 return (FALSE); 316 } 317 if (mon->mtame && (!mon->mflee || mon->mfleetim)) { 318 mon->mflee = 1; /* Rick Richardson */ 319 mon->mfleetim += 10 * rnd(tmp); 320 } 321 if (!hittxt) { 322 if (thrown) 323 /* this assumes that we cannot throw plural things */ 324 hit(xname(obj) /* or: objects[obj->otyp].oc_name */ , 325 mon, exclam(tmp)); 326 else if (Blind) 327 pline("You hit it."); 328 else 329 pline("You hit %s%s", monnam(mon), exclam(tmp)); 330 } 331 if (u.umconf && !thrown) { 332 if (!Blind) { 333 pline("Your hands stop glowing blue."); 334 if (!mon->mfroz && !mon->msleep) 335 pline("%s appears confused.", Monnam(mon)); 336 } 337 mon->mconf = 1; 338 u.umconf = 0; 339 } 340 return (TRUE); /* mon still alive */ 341 } 342 343 /* try to attack; return FALSE if monster evaded */ 344 /* u.dx and u.dy must be set */ 345 int 346 attack(mtmp) 347 struct monst *mtmp; 348 { 349 schar tmp; 350 boolean malive = TRUE; 351 const struct permonst *mdat; 352 mdat = mtmp->data; 353 354 u_wipe_engr(3); /* andrew@orca: prevent unlimited pick-axe 355 * attacks */ 356 357 if (mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep && 358 !mtmp->mconf && mtmp->mcansee && !rn2(7) && 359 (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */ 360 mtmp->mx != u.ux + u.dx || mtmp->my != u.uy + u.dy)) 361 return (FALSE); 362 363 if (mtmp->mimic) { 364 if (!u.ustuck && !mtmp->mflee) 365 u.ustuck = mtmp; 366 switch (levl[u.ux + u.dx][u.uy + u.dy].scrsym) { 367 case '+': 368 pline("The door actually was a Mimic."); 369 break; 370 case '$': 371 pline("The chest was a Mimic!"); 372 break; 373 default: 374 pline("Wait! That's a Mimic!"); 375 } 376 wakeup(mtmp); /* clears mtmp->mimic */ 377 return (TRUE); 378 } 379 wakeup(mtmp); 380 381 if (mtmp->mhide && mtmp->mundetected) { 382 struct obj *obj; 383 384 mtmp->mundetected = 0; 385 if ((obj = o_at(mtmp->mx, mtmp->my)) && !Blind) 386 pline("Wait! There's a %s hiding under %s!", 387 mdat->mname, doname(obj)); 388 return (TRUE); 389 } 390 tmp = u.uluck + u.ulevel + mdat->ac + abon(); 391 if (uwep) { 392 if (uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE) 393 tmp += uwep->spe; 394 if (uwep->otyp == TWO_HANDED_SWORD) 395 tmp -= 1; 396 else if (uwep->otyp == DAGGER) 397 tmp += 2; 398 else if (uwep->otyp == CRYSKNIFE) 399 tmp += 3; 400 else if (uwep->otyp == SPEAR && 401 strchr("XDne", mdat->mlet)) 402 tmp += 2; 403 } 404 if (mtmp->msleep) { 405 mtmp->msleep = 0; 406 tmp += 2; 407 } 408 if (mtmp->mfroz) { 409 tmp += 4; 410 if (!rn2(10)) 411 mtmp->mfroz = 0; 412 } 413 if (mtmp->mflee) 414 tmp += 2; 415 if (u.utrap) 416 tmp -= 3; 417 418 /* with a lot of luggage, your agility diminishes */ 419 tmp -= (inv_weight() + 40) / 20; 420 421 if (tmp <= rnd(20) && !u.uswallow) { 422 if (Blind) 423 pline("You miss it."); 424 else 425 pline("You miss %s.", monnam(mtmp)); 426 } else { 427 /* we hit the monster; be careful: it might die! */ 428 429 if ((malive = hmon(mtmp, uwep, 0)) == TRUE) { 430 /* monster still alive */ 431 if (!rn2(25) && mtmp->mhp < mtmp->mhpmax / 2) { 432 mtmp->mflee = 1; 433 if (!rn2(3)) 434 mtmp->mfleetim = rnd(100); 435 if (u.ustuck == mtmp && !u.uswallow) 436 u.ustuck = 0; 437 } 438 #ifndef NOWORM 439 if (mtmp->wormno) 440 cutworm(mtmp, u.ux + u.dx, u.uy + u.dy, 441 uwep ? uwep->otyp : 0); 442 #endif /* NOWORM */ 443 } 444 if (mdat->mlet == 'a') { 445 if (rn2(2)) { 446 pline("You are splashed by the blob's acid!"); 447 losehp_m(rnd(6), mtmp); 448 if (!rn2(30)) 449 corrode_armor(); 450 } 451 if (!rn2(6)) 452 corrode_weapon(); 453 } 454 } 455 if (malive && mdat->mlet == 'E' && canseemon(mtmp) 456 && !mtmp->mcan && rn2(3)) { 457 if (mtmp->mcansee) { 458 pline("You are frozen by the floating eye's gaze!"); 459 nomul((u.ulevel > 6 || rn2(4)) ? rn1(20, -21) : -200); 460 } else { 461 pline("The blinded floating eye cannot defend itself."); 462 if (!rn2(500)) 463 if ((int) u.uluck > LUCKMIN) 464 u.uluck--; 465 } 466 } 467 return (TRUE); 468 } 469