an object launched by someone/thing other than player attacks a monster; return 1 if the object has stopped moving (hit or its range used up); can anger the monster, if this happened due to hero (eg. exploding bag of holding throwing the items) */
| 318 | can anger the monster, if this happened due to hero (eg. exploding |
| 319 | bag of holding throwing the items) */ |
| 320 | boolean |
| 321 | ohitmon( |
| 322 | struct monst *mtmp, /* accidental target, located at <gb.bhitpos.x,.y> */ |
| 323 | struct obj *otmp, /* missile; might be destroyed by drop_throw */ |
| 324 | int range, /* how much farther will object travel if it misses; |
| 325 | * use -1 to signify to keep going even after hit, |
| 326 | * unless it's gone (for rolling_boulder_traps) */ |
| 327 | boolean verbose) /* give messages even when you can't see what happened */ |
| 328 | { |
| 329 | int damage, tmp; |
| 330 | boolean vis, ismimic, objgone; |
| 331 | struct obj *mon_launcher = gm.marcher ? MON_WEP(gm.marcher) : NULL; |
| 332 | |
| 333 | /* assert(otmp != NULL); */ |
| 334 | gn.notonhead = (gb.bhitpos.x != mtmp->mx || gb.bhitpos.y != mtmp->my); |
| 335 | ismimic = M_AP_TYPE(mtmp) && M_AP_TYPE(mtmp) != M_AP_MONSTER; |
| 336 | vis = cansee(gb.bhitpos.x, gb.bhitpos.y); |
| 337 | if (vis) |
| 338 | observe_object(otmp); |
| 339 | |
| 340 | tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE); |
| 341 | /* High level monsters will be more likely to hit */ |
| 342 | /* This check applies only if this monster is the target |
| 343 | * the archer was aiming at. */ |
| 344 | if (gm.marcher && gm.mtarget == mtmp) { |
| 345 | if (gm.marcher->m_lev > 5) |
| 346 | tmp += gm.marcher->m_lev - 5; |
| 347 | if (mon_launcher && mon_launcher->oartifact) |
| 348 | tmp += spec_abon(mon_launcher, mtmp); |
| 349 | } |
| 350 | if (tmp < rnd(20)) { |
| 351 | if (!ismimic) { |
| 352 | if (vis) |
| 353 | miss(distant_name(otmp, mshot_xname), mtmp); |
| 354 | else if (verbose && !gm.mtarget) |
| 355 | pline("It is missed."); |
| 356 | } |
| 357 | if (!range) { /* Last position; object drops */ |
| 358 | (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my); |
| 359 | return 1; |
| 360 | } |
| 361 | } else if (otmp->oclass == POTION_CLASS) { |
| 362 | if (ismimic) |
| 363 | seemimic(mtmp); |
| 364 | mtmp->msleeping = 0; |
| 365 | /* probably thrown by a monster rather than 'other', but the |
| 366 | distinction only matters when hitting the hero */ |
| 367 | potionhit(mtmp, otmp, POTHIT_OTHER_THROW); |
| 368 | return 1; |
| 369 | } else { |
| 370 | int material = objects[otmp->otyp].oc_material; |
| 371 | boolean harmless = (stone_missile(otmp) && passes_rocks(mtmp->data)); |
| 372 | |
| 373 | damage = dmgval(otmp, mtmp); |
| 374 | if (otmp->otyp == ACID_VENOM && resists_acid(mtmp)) |
| 375 | damage = 0; |
| 376 | #if 0 /* can't use this because we don't have the attacker */ |
| 377 | if (is_orc(mtmp->data) && is_elf(?magr?)) |
no test coverage detected