mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
| 259 | |
| 260 | /* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */ |
| 261 | staticfn void |
| 262 | monshoot(struct monst *mtmp, struct obj *otmp, struct obj *mwep) |
| 263 | { |
| 264 | struct monst *mtarg = gm.mtarget; |
| 265 | int dm = distmin(mtmp->mx, mtmp->my, |
| 266 | mtarg ? mtarg->mx : mtmp->mux, |
| 267 | mtarg ? mtarg->my : mtmp->muy), |
| 268 | multishot = monmulti(mtmp, otmp, mwep); |
| 269 | |
| 270 | /* |
| 271 | * Caller must have called linedup() to set up <gt.tbx, gt.tby>. |
| 272 | */ |
| 273 | |
| 274 | if (canseemon(mtmp)) { |
| 275 | const char *onm; |
| 276 | char onmbuf[BUFSZ], trgbuf[BUFSZ]; |
| 277 | |
| 278 | if (multishot > 1) { |
| 279 | /* "N arrows"; multishot > 1 implies otmp->quan > 1, so |
| 280 | xname()'s result will already be pluralized */ |
| 281 | Sprintf(onmbuf, "%d %s", multishot, xname(otmp)); |
| 282 | onm = onmbuf; |
| 283 | } else { |
| 284 | /* "an arrow" */ |
| 285 | onm = singular(otmp, xname); |
| 286 | onm = obj_is_pname(otmp) ? the(onm) : an(onm); |
| 287 | } |
| 288 | gm.m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE; |
| 289 | Strcpy(trgbuf, mtarg ? some_mon_nam(mtarg) : ""); |
| 290 | set_msg_xy(mtmp->mx, mtmp->my); |
| 291 | pline("%s %s %s%s%s!", Monnam(mtmp), |
| 292 | gm.m_shot.s ? "shoots" : "throws", onm, |
| 293 | mtarg ? " at " : "", trgbuf); |
| 294 | gm.m_shot.o = otmp->otyp; |
| 295 | } else { |
| 296 | gm.m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */ |
| 297 | } |
| 298 | gm.m_shot.n = multishot; |
| 299 | for (gm.m_shot.i = 1; gm.m_shot.i <= gm.m_shot.n; gm.m_shot.i++) { |
| 300 | m_throw(mtmp, mtmp->mx, mtmp->my, sgn(gt.tbx), sgn(gt.tby), dm, otmp); |
| 301 | /* conceptually all N missiles are in flight at once, but |
| 302 | if mtmp gets killed (shot kills adjacent gas spore and |
| 303 | triggers explosion, perhaps), inventory will be dropped |
| 304 | and otmp might go away via merging into another stack */ |
| 305 | if (DEADMONSTER(mtmp) && gm.m_shot.i < gm.m_shot.n) |
| 306 | /* cancel pending shots (perhaps ought to give a message here |
| 307 | since we gave one above about throwing/shooting N missiles) */ |
| 308 | break; /* endmultishot(FALSE); */ |
| 309 | } |
| 310 | /* reset 'gm.m_shot' */ |
| 311 | gm.m_shot.n = gm.m_shot.i = 0; |
| 312 | gm.m_shot.o = STRANGE_OBJECT; |
| 313 | gm.m_shot.s = FALSE; |
| 314 | } |
| 315 | |
| 316 | /* an object launched by someone/thing other than player attacks a monster; |
| 317 | return 1 if the object has stopped moving (hit or its range used up); |
no test coverage detected