1 /* $NetBSD: hack.fight.c,v 1.8 2008/01/28 06:55:41 dholland 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.8 2008/01/28 06:55:41 dholland 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 didhit; 82 schar tmp; 83 boolean vis; 84 85 if (strchr("Eauy", pa->mlet)) 86 return (0); 87 if (magr->mfroz) 88 return (0); /* riv05!a3 */ 89 tmp = pd->ac + pa->mlevel; 90 if (mdef->mconf || mdef->mfroz || mdef->msleep) { 91 tmp += 4; 92 if (mdef->msleep) 93 mdef->msleep = 0; 94 } 95 didhit = (tmp > rnd(20)); 96 if (didhit) 97 mdef->msleep = 0; 98 vis = (cansee(magr->mx, magr->my) && cansee(mdef->mx, mdef->my)); 99 if (vis) { 100 char buf[BUFSZ]; 101 if (mdef->mimic) 102 seemimic(mdef); 103 if (magr->mimic) 104 seemimic(magr); 105 (void) sprintf(buf, "%s %s", Monnam(magr), 106 didhit ? "hits" : "misses"); 107 pline("%s %s.", buf, monnam(mdef)); 108 } else { 109 boolean far = (dist(magr->mx, magr->my) > 15); 110 if (far != far_noise || moves - noisetime > 10) { 111 far_noise = far; 112 noisetime = moves; 113 pline("You hear some noises%s.", 114 far ? " in the distance" : ""); 115 } 116 } 117 if (didhit) { 118 if (magr->data->mlet == 'c' && !magr->cham) { 119 magr->mhpmax += 3; 120 if (vis) 121 pline("%s is turned to stone!", Monnam(mdef)); 122 else if (mdef->mtame) 123 pline("You have a peculiarly sad feeling for a moment, then it passes."); 124 monstone(mdef); 125 didhit = 2; 126 } else if ((mdef->mhp -= d(pa->damn, pa->damd)) < 1) { 127 magr->mhpmax += 1 + rn2(pd->mlevel + 1); 128 if (magr->mtame && magr->mhpmax > 8 * pa->mlevel) { 129 if (pa == &li_dog) 130 magr->data = pa = &dog; 131 else if (pa == &dog) 132 magr->data = pa = &la_dog; 133 } 134 if (vis) 135 pline("%s is killed!", Monnam(mdef)); 136 else if (mdef->mtame) 137 pline("You have a sad feeling for a moment, then it passes."); 138 mondied(mdef); 139 didhit = 2; 140 } 141 } 142 return (didhit); 143 } 144 145 /* drop (perhaps) a cadaver and remove monster */ 146 void 147 mondied(mdef) 148 struct monst *mdef; 149 { 150 const struct permonst *pd = mdef->data; 151 if (letter(pd->mlet) && rn2(3)) { 152 (void) mkobj_at(pd->mlet, mdef->mx, mdef->my); 153 if (cansee(mdef->mx, mdef->my)) { 154 unpmon(mdef); 155 atl(mdef->mx, mdef->my, fobj->olet); 156 } 157 stackobj(fobj); 158 } 159 mondead(mdef); 160 } 161 162 /* drop a rock and remove monster */ 163 void 164 monstone(mdef) 165 struct monst *mdef; 166 { 167 if (strchr(mlarge, mdef->data->mlet)) 168 mksobj_at(ENORMOUS_ROCK, mdef->mx, mdef->my); 169 else 170 mksobj_at(ROCK, mdef->mx, mdef->my); 171 if (cansee(mdef->mx, mdef->my)) { 172 unpmon(mdef); 173 atl(mdef->mx, mdef->my, fobj->olet); 174 } 175 mondead(mdef); 176 } 177 178 179 int 180 fightm(mtmp) 181 struct monst *mtmp; 182 { 183 struct monst *mon; 184 for (mon = fmon; mon; mon = mon->nmon) 185 if (mon != mtmp) { 186 if (DIST(mon->mx, mon->my, mtmp->mx, mtmp->my) < 3) 187 if (rn2(4)) 188 return (hitmm(mtmp, mon)); 189 } 190 return (-1); 191 } 192 193 /* u is hit by sth, but not a monster */ 194 int 195 thitu(tlev, dam, name) 196 int tlev, dam; 197 const char *name; 198 { 199 char buf[BUFSZ]; 200 setan(name, buf); 201 if (u.uac + tlev <= rnd(20)) { 202 if (Blind) 203 pline("It misses."); 204 else 205 pline("You are almost hit by %s!", buf); 206 return (0); 207 } else { 208 if (Blind) 209 pline("You are hit!"); 210 else 211 pline("You are hit by %s!", buf); 212 losehp(dam, name); 213 return (1); 214 } 215 } 216 217 char mlarge[] = "bCDdegIlmnoPSsTUwY',&"; 218 219 boolean 220 hmon(mon, obj, thrown) /* return TRUE if mon still alive */ 221 struct monst *mon; 222 struct obj *obj; 223 int thrown; 224 { 225 int tmp; 226 boolean hittxt = FALSE; 227 228 if (!obj) { 229 tmp = rnd(2); /* attack with bare hands */ 230 if (mon->data->mlet == 'c' && !uarmg) { 231 pline("You hit the cockatrice with your bare hands."); 232 pline("You turn to stone ..."); 233 done_in_by(mon); 234 } 235 } else if (obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE) { 236 if (obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG)) 237 tmp = rnd(2); 238 else { 239 if (strchr(mlarge, mon->data->mlet)) { 240 tmp = rnd(objects[obj->otyp].wldam); 241 if (obj->otyp == TWO_HANDED_SWORD) 242 tmp += d(2, 6); 243 else if (obj->otyp == FLAIL) 244 tmp += rnd(4); 245 } else { 246 tmp = rnd(objects[obj->otyp].wsdam); 247 } 248 tmp += obj->spe; 249 if (!thrown && obj == uwep && obj->otyp == BOOMERANG 250 && !rn2(3)) { 251 pline("As you hit %s, the boomerang breaks into splinters.", 252 monnam(mon)); 253 freeinv(obj); 254 setworn((struct obj *) 0, obj->owornmask); 255 obfree(obj, (struct obj *) 0); 256 obj = NULL; 257 tmp++; 258 } 259 } 260 if (mon->data->mlet == 'O' && obj != NULL && 261 obj->otyp == TWO_HANDED_SWORD && 262 !strcmp(ONAME(obj), "Orcrist")) 263 tmp += rnd(10); 264 } else 265 switch (obj->otyp) { 266 case HEAVY_IRON_BALL: 267 tmp = rnd(25); 268 break; 269 case EXPENSIVE_CAMERA: 270 pline("You succeed in destroying your camera. Congratulations!"); 271 freeinv(obj); 272 if (obj->owornmask) 273 setworn((struct obj *) 0, obj->owornmask); 274 obfree(obj, (struct obj *) 0); 275 return (TRUE); 276 case DEAD_COCKATRICE: 277 pline("You hit %s with the cockatrice corpse.", 278 monnam(mon)); 279 if (mon->data->mlet == 'c') { 280 tmp = 1; 281 hittxt = TRUE; 282 break; 283 } 284 pline("%s is turned to stone!", Monnam(mon)); 285 killed(mon); 286 return (FALSE); 287 case CLOVE_OF_GARLIC: /* no effect against demons */ 288 if (strchr(UNDEAD, mon->data->mlet)) 289 mon->mflee = 1; 290 tmp = 1; 291 break; 292 default: 293 /* non-weapons can damage because of their weight */ 294 /* (but not too much) */ 295 tmp = obj->owt / 10; 296 if (tmp < 1) 297 tmp = 1; 298 else 299 tmp = rnd(tmp); 300 if (tmp > 6) 301 tmp = 6; 302 } 303 304 /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) */ 305 306 tmp += u.udaminc + dbon(); 307 if (u.uswallow) { 308 if ((tmp -= u.uswldtim) <= 0) { 309 pline("Your arms are no longer able to hit."); 310 return (TRUE); 311 } 312 } 313 if (tmp < 1) 314 tmp = 1; 315 mon->mhp -= tmp; 316 if (mon->mhp < 1) { 317 killed(mon); 318 return (FALSE); 319 } 320 if (mon->mtame && (!mon->mflee || mon->mfleetim)) { 321 mon->mflee = 1; /* Rick Richardson */ 322 mon->mfleetim += 10 * rnd(tmp); 323 } 324 if (!hittxt) { 325 if (thrown) { 326 /* this assumes that we cannot throw plural things */ 327 if (obj == NULL) 328 panic("thrown non-object"); 329 hit(xname(obj) /* or: objects[obj->otyp].oc_name */ , 330 mon, exclam(tmp)); 331 } else if (Blind) 332 pline("You hit it."); 333 else 334 pline("You hit %s%s", monnam(mon), exclam(tmp)); 335 } 336 if (u.umconf && !thrown) { 337 if (!Blind) { 338 pline("Your hands stop glowing blue."); 339 if (!mon->mfroz && !mon->msleep) 340 pline("%s appears confused.", Monnam(mon)); 341 } 342 mon->mconf = 1; 343 u.umconf = 0; 344 } 345 return (TRUE); /* mon still alive */ 346 } 347 348 /* try to attack; return FALSE if monster evaded */ 349 /* u.dx and u.dy must be set */ 350 int 351 attack(mtmp) 352 struct monst *mtmp; 353 { 354 schar tmp; 355 boolean malive = TRUE; 356 const struct permonst *mdat; 357 mdat = mtmp->data; 358 359 u_wipe_engr(3); /* andrew@orca: prevent unlimited pick-axe 360 * attacks */ 361 362 if (mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep && 363 !mtmp->mconf && mtmp->mcansee && !rn2(7) && 364 (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */ 365 mtmp->mx != u.ux + u.dx || mtmp->my != u.uy + u.dy)) 366 return (FALSE); 367 368 if (mtmp->mimic) { 369 if (!u.ustuck && !mtmp->mflee) 370 u.ustuck = mtmp; 371 switch (levl[u.ux + u.dx][u.uy + u.dy].scrsym) { 372 case '+': 373 pline("The door actually was a Mimic."); 374 break; 375 case '$': 376 pline("The chest was a Mimic!"); 377 break; 378 default: 379 pline("Wait! That's a Mimic!"); 380 } 381 wakeup(mtmp); /* clears mtmp->mimic */ 382 return (TRUE); 383 } 384 wakeup(mtmp); 385 386 if (mtmp->mhide && mtmp->mundetected) { 387 struct obj *obj; 388 389 mtmp->mundetected = 0; 390 if ((obj = o_at(mtmp->mx, mtmp->my)) && !Blind) 391 pline("Wait! There's a %s hiding under %s!", 392 mdat->mname, doname(obj)); 393 return (TRUE); 394 } 395 tmp = u.uluck + u.ulevel + mdat->ac + abon(); 396 if (uwep) { 397 if (uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE) 398 tmp += uwep->spe; 399 if (uwep->otyp == TWO_HANDED_SWORD) 400 tmp -= 1; 401 else if (uwep->otyp == DAGGER) 402 tmp += 2; 403 else if (uwep->otyp == CRYSKNIFE) 404 tmp += 3; 405 else if (uwep->otyp == SPEAR && 406 strchr("XDne", mdat->mlet)) 407 tmp += 2; 408 } 409 if (mtmp->msleep) { 410 mtmp->msleep = 0; 411 tmp += 2; 412 } 413 if (mtmp->mfroz) { 414 tmp += 4; 415 if (!rn2(10)) 416 mtmp->mfroz = 0; 417 } 418 if (mtmp->mflee) 419 tmp += 2; 420 if (u.utrap) 421 tmp -= 3; 422 423 /* with a lot of luggage, your agility diminishes */ 424 tmp -= (inv_weight() + 40) / 20; 425 426 if (tmp <= rnd(20) && !u.uswallow) { 427 if (Blind) 428 pline("You miss it."); 429 else 430 pline("You miss %s.", monnam(mtmp)); 431 } else { 432 /* we hit the monster; be careful: it might die! */ 433 434 if ((malive = hmon(mtmp, uwep, 0)) == TRUE) { 435 /* monster still alive */ 436 if (!rn2(25) && mtmp->mhp < mtmp->mhpmax / 2) { 437 mtmp->mflee = 1; 438 if (!rn2(3)) 439 mtmp->mfleetim = rnd(100); 440 if (u.ustuck == mtmp && !u.uswallow) 441 u.ustuck = 0; 442 } 443 #ifndef NOWORM 444 if (mtmp->wormno) 445 cutworm(mtmp, u.ux + u.dx, u.uy + u.dy, 446 uwep ? uwep->otyp : 0); 447 #endif /* NOWORM */ 448 } 449 if (mdat->mlet == 'a') { 450 if (rn2(2)) { 451 pline("You are splashed by the blob's acid!"); 452 losehp_m(rnd(6), mtmp); 453 if (!rn2(30)) 454 corrode_armor(); 455 } 456 if (!rn2(6)) 457 corrode_weapon(); 458 } 459 } 460 if (malive && mdat->mlet == 'E' && canseemon(mtmp) 461 && !mtmp->mcan && rn2(3)) { 462 if (mtmp->mcansee) { 463 pline("You are frozen by the floating eye's gaze!"); 464 nomul((u.ulevel > 6 || rn2(4)) ? rn1(20, -21) : -200); 465 } else { 466 pline("The blinded floating eye cannot defend itself."); 467 if (!rn2(500)) 468 if ((int) u.uluck > LUCKMIN) 469 u.uluck--; 470 } 471 } 472 return (TRUE); 473 } 474