1 /* NetHack 3.6 dothrow.c $NHDT-Date: 1455140444 2016/02/10 21:40:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.118 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* Contains code for 't' (throw) */
9 STATIC_DCL
int FDECL(throw_obj
, (struct obj
*, int));
10 STATIC_DCL boolean
FDECL(ok_to_throw
, (int *));
11 STATIC_DCL
void NDECL(autoquiver
);
12 STATIC_DCL
int FDECL(gem_accept
, (struct monst
*, struct obj
*));
13 STATIC_DCL
void FDECL(tmiss
, (struct obj
*, struct monst
*, BOOLEAN_P
));
14 STATIC_DCL
int FDECL(throw_gold
, (struct obj
*));
15 STATIC_DCL
void FDECL(check_shop_obj
, (struct obj
*, XCHAR_P
, XCHAR_P
,
17 STATIC_DCL
void FDECL(breakmsg
, (struct obj
*, BOOLEAN_P
));
18 STATIC_DCL boolean
FDECL(toss_up
, (struct obj
*, BOOLEAN_P
));
19 STATIC_DCL
void FDECL(sho_obj_return_to_u
, (struct obj
* obj
));
20 STATIC_DCL boolean
FDECL(mhurtle_step
, (genericptr_t
, int, int));
22 static NEARDATA
const char toss_objs
[] = { ALLOW_COUNT
, COIN_CLASS
,
23 ALL_CLASSES
, WEAPON_CLASS
, 0 };
24 /* different default choices when wielding a sling (gold must be included) */
25 static NEARDATA
const char bullets
[] = { ALLOW_COUNT
, COIN_CLASS
, ALL_CLASSES
,
28 /* thrownobj (decl.c) tracks an object until it lands */
30 extern boolean notonhead
; /* for long worms */
32 /* Throw the selected object, asking for direction */
34 throw_obj(obj
, shotlimit
)
42 boolean twoweap
, weakmultishot
;
44 /* ask "in what direction?" */
45 if (!getdir((char *) 0)) {
46 /* No direction specified, so cancel the throw;
47 * might need to undo an object split.
48 * We used to use freeinv(obj),addinv(obj) here, but that can
49 * merge obj into another stack--usually quiver--even if it hadn't
50 * been split from there (possibly triggering a panic in addinv),
51 * and freeinv+addinv potentially has other side-effects.
53 if (obj
->o_id
== context
.objsplit
.parent_oid
54 || obj
->o_id
== context
.objsplit
.child_oid
)
55 (void) unsplitobj(obj
);
56 return 0; /* no time passes */
60 * Throwing money is usually for getting rid of it when
61 * a leprechaun approaches, or for bribing an oncoming
62 * angry monster. So throw the whole object.
64 * If the money is in quiver, throw one coin at a time,
65 * possibly using a sling.
67 if (obj
->oclass
== COIN_CLASS
&& obj
!= uquiver
)
68 return throw_gold(obj
);
70 if (!canletgo(obj
, "throw"))
72 if (obj
->oartifact
== ART_MJOLLNIR
&& obj
!= uwep
) {
73 pline("%s must be wielded before it can be thrown.", The(xname(obj
)));
76 if ((obj
->oartifact
== ART_MJOLLNIR
&& ACURR(A_STR
) < STR19(25))
77 || (obj
->otyp
== BOULDER
&& !throws_rocks(youmonst
.data
))) {
78 pline("It's too heavy.");
81 if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
82 You("cannot throw an object at yourself.");
86 if (!uarmg
&& obj
->otyp
== CORPSE
&& touch_petrifies(&mons
[obj
->corpsenm
])
87 && !Stone_resistance
) {
88 You("throw %s with your bare %s.",
89 corpse_xname(obj
, (const char *) 0, CXN_PFX_THE
),
90 /* throwing with one hand, but pluralize since the
91 expression "with your bare hands" sounds better */
92 makeplural(body_part(HAND
)));
93 Sprintf(killer
.name
, "throwing %s bare-handed", killer_xname(obj
));
94 instapetrify(killer
.name
);
100 if (is_wet_towel(obj
))
101 dry_a_towel(obj
, -1, FALSE
);
103 /* Multishot calculations
104 * (potential volley of up to N missiles; default for N is 1)
107 skill
= objects
[obj
->otyp
].oc_skill
;
108 if (obj
->quan
> 1L /* no point checking if there's only 1 */
109 /* ammo requires corresponding launcher be wielded */
110 && (is_ammo(obj
) ? matching_launcher(obj
, uwep
)
111 /* otherwise any stackable (non-ammo) weapon */
112 : obj
->oclass
== WEAPON_CLASS
)
113 && !(Confusion
|| Stunned
)) {
114 /* some roles don't get a volley bonus until becoming expert */
115 weakmultishot
= (Role_if(PM_WIZARD
) || Role_if(PM_PRIEST
)
116 || (Role_if(PM_HEALER
) && skill
!= P_KNIFE
)
117 || (Role_if(PM_TOURIST
) && skill
!= -P_DART
)
118 /* poor dexterity also inhibits multishot */
119 || Fumbling
|| ACURR(A_DEX
) <= 6);
121 /* Bonus if the player is proficient in this weapon... */
122 switch (P_SKILL(weapon_type(obj
))) {
130 default: /* basic or unskilled: no bonus */
133 /* ...or is using a special weapon for their role... */
134 switch (Role_switch
) {
136 /* give bonus for low-tech gear */
137 if (skill
== -P_SLING
|| skill
== P_SPEAR
)
141 /* allow higher volley count despite skill limitation */
142 if (skill
== -P_SHURIKEN
)
146 /* arbitrary; encourage use of other missiles beside daggers */
147 if (skill
!= P_DAGGER
)
151 /* possibly should add knives... */
152 if (skill
== P_DAGGER
)
156 /* role-specific launcher and its ammo */
157 if (obj
->otyp
== YA
&& uwep
&& uwep
->otyp
== YUMI
)
161 break; /* No bonus */
163 /* ...or using their race's special bow; no bonus for spears */
165 switch (Race_switch
) {
167 if (obj
->otyp
== ELVEN_ARROW
&& uwep
168 && uwep
->otyp
== ELVEN_BOW
)
172 if (obj
->otyp
== ORCISH_ARROW
&& uwep
173 && uwep
->otyp
== ORCISH_BOW
)
177 /* arbitrary; there isn't any gnome-specific gear */
178 if (skill
== -P_CROSSBOW
)
184 break; /* No bonus */
187 /* crossbows are slow to load and probably shouldn't allow multiple
188 shots at all, but that would result in players never using them;
189 instead, high strength is necessary to load and shoot quickly */
190 if (multishot
> 1 && skill
== -P_CROSSBOW
191 && ammo_and_launcher(obj
, uwep
)
192 && (int) ACURRSTR
< (Race_if(PM_GNOME
) ? 16 : 18))
193 multishot
= rnd(multishot
);
195 multishot
= rnd(multishot
);
196 if ((long) multishot
> obj
->quan
)
197 multishot
= (int) obj
->quan
;
198 if (shotlimit
> 0 && multishot
> shotlimit
)
199 multishot
= shotlimit
;
202 m_shot
.s
= ammo_and_launcher(obj
, uwep
) ? TRUE
: FALSE
;
203 /* give a message if shooting more than one, or if player
204 attempted to specify a count */
205 if (multishot
> 1 || shotlimit
> 0) {
206 /* "You shoot N arrows." or "You throw N daggers." */
207 You("%s %d %s.", m_shot
.s
? "shoot" : "throw",
208 multishot
, /* (might be 1 if player gave shotlimit) */
209 (multishot
== 1) ? singular(obj
, xname
) : xname(obj
));
212 wep_mask
= obj
->owornmask
;
213 m_shot
.o
= obj
->otyp
;
214 m_shot
.n
= multishot
;
215 for (m_shot
.i
= 1; m_shot
.i
<= m_shot
.n
; m_shot
.i
++) {
217 /* split this object off from its slot if necessary */
218 if (obj
->quan
> 1L) {
219 otmp
= splitobj(obj
, 1L);
223 remove_worn_item(otmp
, FALSE
);
226 throwit(otmp
, wep_mask
, twoweap
);
228 m_shot
.n
= m_shot
.i
= 0;
229 m_shot
.o
= STRANGE_OBJECT
;
235 /* common to dothrow() and dofire() */
237 ok_to_throw(shotlimit_p
)
238 int *shotlimit_p
; /* (see dothrow()) */
240 /* kludge to work around parse()'s pre-decrement of `multi' */
241 *shotlimit_p
= (multi
|| save_cm
) ? multi
+ 1 : 0;
242 multi
= 0; /* reset; it's been used up */
244 if (notake(youmonst
.data
)) {
245 You("are physically incapable of throwing or shooting anything.");
247 } else if (nohands(youmonst
.data
)) {
248 You_cant("throw or shoot without hands."); /* not body_part(HAND) */
250 /*[what about !freehand(), aside from cursed missile launcher?]*/
252 if (check_capacity((char *) 0))
257 /* t command - throw */
261 register struct obj
*obj
;
265 * Since some characters shoot multiple missiles at one time,
266 * allow user to specify a count prefix for 'f' or 't' to limit
267 * number of items thrown (to avoid possibly hitting something
268 * behind target after killing it, or perhaps to conserve ammo).
270 * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)''
271 * and took 3 turns. Now it means ``t(shoot at most 3 missiles)''.
273 * [3.6.0: shot count setup has been moved into ok_to_throw().]
275 if (!ok_to_throw(&shotlimit
))
278 obj
= getobj(uslinging() ? bullets
: toss_objs
, "throw");
279 /* it is also possible to throw food */
280 /* (or jewels, or iron balls... ) */
282 return obj
? throw_obj(obj
, shotlimit
) : 0;
285 /* KMH -- Automatically fill quiver */
286 /* Suggested by Jeffrey Bay <jbay@convex.hp.com> */
290 struct obj
*otmp
, *oammo
= 0, *omissile
= 0, *omisc
= 0, *altammo
= 0;
295 /* Scan through the inventory */
296 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
297 if (otmp
->owornmask
|| otmp
->oartifact
|| !otmp
->dknown
) {
299 } else if (otmp
->otyp
== ROCK
300 /* seen rocks or known flint or known glass */
301 || (otmp
->otyp
== FLINT
302 && objects
[otmp
->otyp
].oc_name_known
)
303 || (otmp
->oclass
== GEM_CLASS
304 && objects
[otmp
->otyp
].oc_material
== GLASS
305 && objects
[otmp
->otyp
].oc_name_known
)) {
308 else if (ammo_and_launcher(otmp
, uswapwep
))
312 } else if (otmp
->oclass
== GEM_CLASS
) {
313 ; /* skip non-rock gems--they're ammo but
314 player has to select them explicitly */
315 } else if (is_ammo(otmp
)) {
316 if (ammo_and_launcher(otmp
, uwep
))
317 /* Ammo matched with launcher (bow+arrow, crossbow+bolt) */
319 else if (ammo_and_launcher(otmp
, uswapwep
))
322 /* Mismatched ammo (no better than an ordinary weapon) */
324 } else if (is_missile(otmp
)) {
325 /* Missile (dart, shuriken, etc.) */
327 } else if (otmp
->oclass
== WEAPON_CLASS
&& throwing_weapon(otmp
)) {
328 /* Ordinary weapon */
329 if (objects
[otmp
->otyp
].oc_skill
== P_DAGGER
&& !omissile
)
336 /* Pick the best choice */
349 /* f command -- fire: throw from the quiver */
357 * Same as dothrow(), except we use quivered missile instead
358 * of asking what to throw/shoot.
360 * If quiver is empty, we use autoquiver to fill it when the
361 * corresponding option is on. If the option is off or if
362 * autoquiver doesn't select anything, we ask what to throw.
363 * For the last, if player's response is a stack, we put
364 * that stack into quiver slot provided it's not wielded.
366 if (!ok_to_throw(&shotlimit
))
369 if ((obj
= uquiver
) == 0) {
370 if (!flags
.autoquiver
) {
371 You("have no ammunition readied.");
374 if ((obj
= uquiver
) == 0)
375 You("have nothing appropriate for your quiver.");
377 /* if autoquiver is disabled or has failed, prompt for missile;
378 fill quiver with it if it's not wielded */
380 obj
= getobj(uslinging() ? bullets
: toss_objs
, "throw");
381 /* Q command doesn't allow gold in quiver */
382 if (obj
&& !obj
->owornmask
&& obj
->oclass
!= COIN_CLASS
)
383 setuqwep(obj
); /* demi-autoquiver */
385 /* give feedback if quiver has now been filled */
387 uquiver
->owornmask
&= ~W_QUIVER
; /* less verbose */
388 prinv("You ready:", uquiver
, 0L);
389 uquiver
->owornmask
|= W_QUIVER
;
393 return obj
? throw_obj(obj
, shotlimit
) : 0;
396 /* if in midst of multishot shooting/throwing, stop early */
398 endmultishot(verbose
)
401 if (m_shot
.i
< m_shot
.n
) {
402 if (verbose
&& !context
.mon_moving
) {
403 You("stop %s after the %d%s %s.",
404 m_shot
.s
? "firing" : "throwing", m_shot
.i
, ordin(m_shot
.i
),
405 m_shot
.s
? "shot" : "toss");
407 m_shot
.n
= m_shot
.i
; /* make current shot be the last */
412 * Object hits floor at hero's feet. Called from drop() and throwit().
416 register struct obj
*obj
;
418 if (IS_SOFT(levl
[u
.ux
][u
.uy
].typ
) || u
.uinwater
) {
422 if (IS_ALTAR(levl
[u
.ux
][u
.uy
].typ
))
425 pline("%s hit%s the %s.", Doname2(obj
), (obj
->quan
== 1L) ? "s" : "",
426 surface(u
.ux
, u
.uy
));
428 if (hero_breaks(obj
, u
.ux
, u
.uy
, TRUE
))
430 if (ship_object(obj
, u
.ux
, u
.uy
, FALSE
))
436 * Walk a path from src_cc to dest_cc, calling a proc for each location
437 * except the starting one. If the proc returns FALSE, stop walking
438 * and return FALSE. If stopped early, dest_cc will be the location
439 * before the failed callback.
442 walk_path(src_cc
, dest_cc
, check_proc
, arg
)
445 boolean
FDECL((*check_proc
), (genericptr_t
, int, int));
448 int x
, y
, dx
, dy
, x_change
, y_change
, err
, i
, prev_x
, prev_y
;
449 boolean keep_going
= TRUE
;
451 /* Use Bresenham's Line Algorithm to walk from src to dest */
452 dx
= dest_cc
->x
- src_cc
->x
;
453 dy
= dest_cc
->y
- src_cc
->y
;
454 prev_x
= x
= src_cc
->x
;
455 prev_y
= y
= src_cc
->y
;
479 /* check for early exit condition */
480 if (!(keep_going
= (*check_proc
)(arg
, x
, y
)))
493 /* check for early exit condition */
494 if (!(keep_going
= (*check_proc
)(arg
, x
, y
)))
500 return TRUE
; /* successful */
508 * Single step for the hero flying through the air from jumping, flying,
509 * etc. Called from hurtle() and jump() via walk_path(). We expect the
510 * argument to be a pointer to an integer -- the range -- which is
511 * used in the calculation of points off if we hit something.
513 * Bumping into monsters won't cause damage but will wake them and make
514 * them angry. Auto-pickup isn't done, since you don't have control over
515 * your movements at the time.
517 * Possible additions/changes:
518 * o really attack monster if we hit one
519 * o set stunned if we hit a wall or door
520 * o reset nomul when we stop
521 * o creepy feeling if pass through monster (if ever implemented...)
523 * o let jumps go over boulders
526 hurtle_step(arg
, x
, y
)
530 int ox
, oy
, *range
= (int *) arg
;
533 boolean may_pass
= TRUE
;
538 You_feel("the spirits holding you back.");
540 } else if (!in_out_region(x
, y
)) {
542 } else if (*range
== 0) {
543 return FALSE
; /* previous step wants to stop now */
546 if (!Passes_walls
|| !(may_pass
= may_passwall(x
, y
))) {
547 boolean odoor_diag
= (IS_DOOR(levl
[x
][y
].typ
)
548 && (levl
[x
][y
].doormask
& D_ISOPEN
)
549 && (u
.ux
- x
) && (u
.uy
- y
));
551 if (IS_ROCK(levl
[x
][y
].typ
) || closed_door(x
, y
) || odoor_diag
) {
555 You("hit the door edge!");
557 if (IS_TREE(levl
[x
][y
].typ
))
558 s
= "bumping into a tree";
559 else if (IS_ROCK(levl
[x
][y
].typ
))
560 s
= "bumping into a wall";
562 s
= "bumping into a door";
563 dmg
= rnd(2 + *range
);
564 losehp(Maybe_Half_Phys(dmg
), s
, KILLED_BY
);
565 wake_nearto(x
,y
, 10);
568 if (levl
[x
][y
].typ
== IRONBARS
) {
569 You("crash into some iron bars. Ouch!");
570 dmg
= rnd(2 + *range
);
571 losehp(Maybe_Half_Phys(dmg
), "crashing into iron bars",
573 wake_nearto(x
,y
, 20);
576 if ((obj
= sobj_at(BOULDER
, x
, y
)) != 0) {
577 You("bump into a %s. Ouch!", xname(obj
));
578 dmg
= rnd(2 + *range
);
579 losehp(Maybe_Half_Phys(dmg
), "bumping into a boulder", KILLED_BY
);
580 wake_nearto(x
,y
, 10);
584 /* did we hit a no-dig non-wall position? */
585 You("smack into something!");
586 dmg
= rnd(2 + *range
);
587 losehp(Maybe_Half_Phys(dmg
), "touching the edge of the universe",
589 wake_nearto(x
,y
, 10);
592 if ((u
.ux
- x
) && (u
.uy
- y
) && bad_rock(youmonst
.data
, u
.ux
, y
)
593 && bad_rock(youmonst
.data
, x
, u
.uy
)) {
595 (invent
&& (inv_weight() + weight_cap() > 600));
596 /* Move at a diagonal. */
597 if (bigmonst(youmonst
.data
) || too_much
) {
598 You("%sget forcefully wedged into a crevice.",
599 too_much
? "and all your belongings " : "");
600 dmg
= rnd(2 + *range
);
601 losehp(Maybe_Half_Phys(dmg
), "wedging into a narrow crevice",
603 wake_nearto(x
,y
, 10);
609 if ((mon
= m_at(x
, y
)) != 0) {
610 You("bump into %s.", a_monnam(mon
));
612 wake_nearto(x
,y
, 10);
615 if ((u
.ux
- x
) && (u
.uy
- y
) && bad_rock(youmonst
.data
, u
.ux
, y
)
616 && bad_rock(youmonst
.data
, x
, u
.uy
)) {
617 /* Move at a diagonal. */
619 You("come to an abrupt halt!");
624 /* Caller has already determined that dragging the ball is allowed */
625 if (Punished
&& uball
->where
== OBJ_FLOOR
) {
627 xchar ballx
, bally
, chainx
, chainy
;
630 if (drag_ball(x
, y
, &bc_control
, &ballx
, &bally
, &chainx
,
631 &chainy
, &cause_delay
, TRUE
))
632 move_bc(0, bc_control
, ballx
, bally
, chainx
, chainy
);
637 u_on_newpos(x
, y
); /* set u.<ux,uy>, u.usteed-><mx,my>; cliparound(); */
638 newsym(ox
, oy
); /* update old position */
639 vision_recalc(1); /* update for new position */
642 if (levl
[x
][y
].typ
== WATER
&& Is_waterlevel(&u
.uz
)) {
649 * Each trap should really trigger on the recoil if
650 * it would trigger during normal movement. However,
651 * not all the possible side-effects of this are
652 * tested [as of 3.4.0] so we trigger those that
653 * we have tested, and offer a message for the
654 * ones that we have not yet tested.
656 if ((ttmp
= t_at(x
, y
)) != 0) {
657 if (ttmp
->ttyp
== MAGIC_PORTAL
) {
660 } else if (ttmp
->ttyp
== VIBRATING_SQUARE
) {
661 pline("The ground vibrates as you pass it.");
662 dotrap(ttmp
, 0); /* doesn't print messages */
663 } else if (ttmp
->ttyp
== FIRE_TRAP
) {
665 } else if ((ttmp
->ttyp
== PIT
|| ttmp
->ttyp
== SPIKED_PIT
666 || ttmp
->ttyp
== HOLE
|| ttmp
->ttyp
== TRAPDOOR
)
668 /* Air currents overcome the recoil */
674 You("pass right over %s.",
675 an(defsyms
[trap_to_defsym(ttmp
->ttyp
)].explanation
));
678 if (--*range
< 0) /* make sure our range never goes negative */
686 mhurtle_step(arg
, x
, y
)
690 struct monst
*mon
= (struct monst
*) arg
;
692 /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
693 * rather than just stopping before.
695 if (goodpos(x
, y
, mon
, 0) && m_in_out_region(mon
, x
, y
)) {
696 remove_monster(mon
->mx
, mon
->my
);
697 newsym(mon
->mx
, mon
->my
);
698 place_monster(mon
, x
, y
);
699 newsym(mon
->mx
, mon
->my
);
708 * The player moves through the air for a few squares as a result of
709 * throwing or kicking something.
711 * dx and dy should be the direction of the hurtle, not of the original
712 * kick or throw and be only.
715 hurtle(dx
, dy
, range
, verbose
)
721 /* The chain is stretched vertically, so you shouldn't be able to move
722 * very far diagonally. The premise that you should be able to move one
723 * spot leads to calculations that allow you to only move one spot away
724 * from the ball, if you are levitating over the ball, or one spot
725 * towards the ball, if you are at the end of the chain. Rather than
726 * bother with all of that, assume that there is no slack in the chain
727 * for diagonal movement, give the player a message and return.
729 if (Punished
&& !carried(uball
)) {
730 You_feel("a tug from the iron ball.");
733 } else if (u
.utrap
) {
734 You("are anchored by the %s.",
735 u
.utraptype
== TT_WEB
737 : u
.utraptype
== TT_LAVA
739 : u
.utraptype
== TT_INFLOOR
740 ? surface(u
.ux
, u
.uy
)
741 : u
.utraptype
== TT_BURIEDBALL
? "buried ball"
747 /* make sure dx and dy are [-1,0,1] */
751 if (!range
|| (!dx
&& !dy
) || u
.ustuck
)
752 return; /* paranoia */
755 multi_reason
= "moving through the air";
756 nomovemsg
= ""; /* it just happens */
758 You("%s in the opposite direction.", range
> 1 ? "hurtle" : "float");
759 /* if we're in the midst of shooting multiple projectiles, stop */
764 /* this setting of cc is only correct if dx and dy are [-1,0,1] only */
765 cc
.x
= u
.ux
+ (dx
* range
);
766 cc
.y
= u
.uy
+ (dy
* range
);
767 (void) walk_path(&uc
, &cc
, hurtle_step
, (genericptr_t
) &range
);
770 /* Move a monster through the air for a few squares.
773 mhurtle(mon
, dx
, dy
, range
)
779 /* At the very least, debilitate the monster */
783 /* Is the monster stuck or too heavy to push?
784 * (very large monsters have too much inertia, even floaters and flyers)
786 if (mon
->data
->msize
>= MZ_HUGE
|| mon
== u
.ustuck
|| mon
->mtrapped
)
789 /* Make sure dx and dy are [-1,0,1] */
792 if (!range
|| (!dx
&& !dy
))
793 return; /* paranoia */
794 /* don't let grid bugs be hurtled diagonally */
795 if (dx
&& dy
&& NODIAG(monsndx(mon
->data
)))
798 /* Send the monster along the path */
801 cc
.x
= mon
->mx
+ (dx
* range
);
802 cc
.y
= mon
->my
+ (dy
* range
);
803 (void) walk_path(&mc
, &cc
, mhurtle_step
, (genericptr_t
) mon
);
808 check_shop_obj(obj
, x
, y
, broken
)
813 struct monst
*shkp
= shop_keeper(*u
.ushops
);
818 if (broken
|| !costly_spot(x
, y
)
819 || *in_rooms(x
, y
, SHOPBASE
) != *u
.ushops
) {
820 /* thrown out of a shop or into a different shop */
822 (void) stolen_value(obj
, u
.ux
, u
.uy
, (boolean
) shkp
->mpeaceful
,
827 if (costly_spot(u
.ux
, u
.uy
) && costly_spot(x
, y
)) {
829 subfrombill(obj
, shkp
);
830 else if (x
!= shkp
->mx
|| y
!= shkp
->my
)
837 * Hero tosses an object upwards with appropriate consequences.
839 * Returns FALSE if the object is gone.
842 toss_up(obj
, hitsroof
)
847 boolean petrifier
= ((obj
->otyp
== EGG
|| obj
->otyp
== CORPSE
)
848 && touch_petrifies(&mons
[obj
->corpsenm
]));
849 /* note: obj->quan == 1 */
851 if (!has_ceiling(&u
.uz
)) {
852 action
= "flies up into"; /* into "the sky" or "the water above" */
853 } else if (hitsroof
) {
854 if (breaktest(obj
)) {
855 pline("%s hits the %s.", Doname2(obj
), ceiling(u
.ux
, u
.uy
));
856 breakmsg(obj
, !Blind
);
857 breakobj(obj
, u
.ux
, u
.uy
, TRUE
, TRUE
);
862 action
= "almost hits";
864 pline("%s %s the %s, then falls back on top of your %s.", Doname2(obj
),
865 action
, ceiling(u
.ux
, u
.uy
), body_part(HEAD
));
867 /* object now hits you */
869 if (obj
->oclass
== POTION_CLASS
) {
870 potionhit(&youmonst
, obj
, TRUE
);
871 } else if (breaktest(obj
)) {
872 int otyp
= obj
->otyp
;
875 /* need to check for blindness result prior to destroying obj */
876 blindinc
= ((otyp
== CREAM_PIE
|| otyp
== BLINDING_VENOM
)
877 /* AT_WEAP is ok here even if attack type was AT_SPIT */
878 && can_blnd(&youmonst
, &youmonst
, AT_WEAP
, obj
))
881 breakmsg(obj
, !Blind
);
882 breakobj(obj
, u
.ux
, u
.uy
, TRUE
, TRUE
);
883 obj
= 0; /* it's now gone */
886 if (petrifier
&& !Stone_resistance
887 && !(poly_when_stoned(youmonst
.data
)
888 && polymon(PM_STONE_GOLEM
))) {
889 /* egg ends up "all over your face"; perhaps
890 visored helmet should still save you here */
892 Your("%s fails to protect you.", helm_simple_name(uarmh
));
897 pline("You've got it all over your %s!", body_part(FACE
));
899 if (otyp
== BLINDING_VENOM
&& !Blind
)
900 pline("It blinds you!");
901 u
.ucreamed
+= blindinc
;
902 make_blinded(Blinded
+ (long) blindinc
, FALSE
);
904 Your1(vision_clears
);
911 } else { /* neither potion nor other breaking object */
912 boolean less_damage
= uarmh
&& is_metallic(uarmh
), artimsg
= FALSE
;
913 int dmg
= dmgval(obj
, &youmonst
);
916 /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
917 artimsg
= artifact_hit((struct monst
*) 0, &youmonst
, obj
, &dmg
,
920 if (!dmg
) { /* probably wasn't a weapon; base damage on weight */
921 dmg
= (int) obj
->owt
/ 100;
926 if (youmonst
.data
== &mons
[PM_SHADE
]
927 && objects
[obj
->otyp
].oc_material
!= SILVER
)
930 if (dmg
> 1 && less_damage
)
935 dmg
= 0; /* beware negative rings of increase damage */
936 dmg
= Maybe_Half_Phys(dmg
);
939 if (less_damage
&& dmg
< (Upolyd
? u
.mh
: u
.uhp
)) {
941 pline("Fortunately, you are wearing a hard helmet.");
942 /* helmet definitely protects you when it blocks petrification
944 } else if (!petrifier
) {
946 Your("%s does not protect you.", helm_simple_name(uarmh
));
948 } else if (petrifier
&& !Stone_resistance
949 && !(poly_when_stoned(youmonst
.data
)
950 && polymon(PM_STONE_GOLEM
))) {
952 killer
.format
= KILLED_BY
;
953 Strcpy(killer
.name
, "elementary physics"); /* "what goes up..." */
954 You("turn to stone.");
956 dropy(obj
); /* bypass most of hitfloor() */
957 thrownobj
= 0; /* now either gone or on floor */
959 return obj
? TRUE
: FALSE
;
963 losehp(Maybe_Half_Phys(dmg
), "falling object", KILLED_BY_AN
);
968 /* return true for weapon meant to be thrown; excludes ammo */
973 return (boolean
) (is_missile(obj
) || is_spear(obj
)
974 /* daggers and knife (excludes scalpel) */
975 || (is_blade(obj
) && !is_sword(obj
)
976 && (objects
[obj
->otyp
].oc_dir
& PIERCE
))
977 /* special cases [might want to add AXE] */
978 || obj
->otyp
== WAR_HAMMER
|| obj
->otyp
== AKLYS
);
981 /* the currently thrown object is returning to you (not for boomerangs) */
983 sho_obj_return_to_u(obj
)
986 /* might already be our location (bounced off a wall) */
987 if (bhitpos
.x
!= u
.ux
|| bhitpos
.y
!= u
.uy
) {
988 int x
= bhitpos
.x
- u
.dx
, y
= bhitpos
.y
- u
.dy
;
990 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
991 while (x
!= u
.ux
|| y
!= u
.uy
) {
1001 /* throw an object, NB: obj may be consumed in the process */
1003 throwit(obj
, wep_mask
, twoweap
)
1005 long wep_mask
; /* used to re-equip returning boomerang */
1007 twoweap
; /* used to restore twoweapon mode if wielded weapon returns */
1009 register struct monst
*mon
;
1010 register int range
, urange
;
1011 boolean crossbowing
, impaired
= (Confusion
|| Stunned
|| Blind
1012 || Hallucination
|| Fumbling
);
1014 notonhead
= FALSE
; /* reset potentially stale value */
1015 if ((obj
->cursed
|| obj
->greased
) && (u
.dx
|| u
.dy
) && !rn2(7)) {
1016 boolean slipok
= TRUE
;
1017 if (ammo_and_launcher(obj
, uwep
))
1018 pline("%s!", Tobjnam(obj
, "misfire"));
1020 /* only slip if it's greased or meant to be thrown */
1021 if (obj
->greased
|| throwing_weapon(obj
))
1022 /* BUG: this message is grammatically incorrect if obj has
1023 a plural name; greased gloves or boots for instance. */
1024 pline("%s as you throw it!", Tobjnam(obj
, "slip"));
1037 if ((u
.dx
|| u
.dy
|| (u
.dz
< 1))
1038 && calc_capacity((int) obj
->owt
) > SLT_ENCUMBER
1039 && (Upolyd
? (u
.mh
< 5 && u
.mh
!= u
.mhmax
)
1040 : (u
.uhp
< 10 && u
.uhp
!= u
.uhpmax
))
1041 && obj
->owt
> (unsigned) ((Upolyd
? u
.mh
: u
.uhp
) * 2)
1042 && !Is_airlevel(&u
.uz
)) {
1043 You("have so little stamina, %s drops from your grasp.",
1045 exercise(A_CON
, FALSE
);
1051 thrownobj
->was_thrown
= 1;
1055 bhitpos
.x
= mon
->mx
;
1056 bhitpos
.y
= mon
->my
;
1058 if (u
.dz
< 0 && Role_if(PM_VALKYRIE
) && obj
->oartifact
== ART_MJOLLNIR
1060 pline("%s the %s and returns to your hand!", Tobjnam(obj
, "hit"),
1061 ceiling(u
.ux
, u
.uy
));
1063 (void) encumber_msg();
1065 u
.twoweap
= twoweap
;
1066 } else if (u
.dz
< 0) {
1067 (void) toss_up(obj
, rn2(5) && !Underwater
);
1068 } else if (u
.dz
> 0 && u
.usteed
&& obj
->oclass
== POTION_CLASS
1070 /* alternative to prayer or wand of opening/spell of knock
1071 for dealing with cursed saddle: throw holy water > */
1072 potionhit(u
.usteed
, obj
, TRUE
);
1076 thrownobj
= (struct obj
*) 0;
1079 } else if (obj
->otyp
== BOOMERANG
&& !Underwater
) {
1080 if (Is_airlevel(&u
.uz
) || Levitation
)
1081 hurtle(-u
.dx
, -u
.dy
, 1, TRUE
);
1082 mon
= boomhit(obj
, u
.dx
, u
.dy
);
1083 if (mon
== &youmonst
) { /* the thing was caught */
1084 exercise(A_DEX
, TRUE
);
1086 (void) encumber_msg();
1087 if (wep_mask
&& !(obj
->owornmask
& wep_mask
)) {
1088 setworn(obj
, wep_mask
);
1089 u
.twoweap
= twoweap
;
1091 thrownobj
= (struct obj
*) 0;
1095 /* crossbow range is independent of strength */
1097 (ammo_and_launcher(obj
, uwep
) && weapon_type(uwep
) == P_CROSSBOW
);
1098 urange
= (crossbowing
? 18 : (int) ACURRSTR
) / 2;
1099 /* balls are easy to throw or at least roll;
1100 * also, this insures the maximum range of a ball is greater
1101 * than 1, so the effects from throwing attached balls are
1104 if (obj
->otyp
== HEAVY_IRON_BALL
)
1105 range
= urange
- (int) (obj
->owt
/ 100);
1107 range
= urange
- (int) (obj
->owt
/ 40);
1111 else if (range
>= 5)
1118 if (ammo_and_launcher(obj
, uwep
)) {
1123 } else if (obj
->oclass
!= GEM_CLASS
)
1127 if (Is_airlevel(&u
.uz
) || Levitation
) {
1128 /* action, reaction... */
1137 if (obj
->otyp
== BOULDER
)
1138 range
= 20; /* you must be giant */
1139 else if (obj
->oartifact
== ART_MJOLLNIR
)
1140 range
= (range
+ 1) / 2; /* it's heavy */
1141 else if (obj
== uball
&& u
.utrap
&& u
.utraptype
== TT_INFLOOR
)
1147 mon
= bhit(u
.dx
, u
.dy
, range
, THROWN_WEAPON
,
1148 (int FDECL((*), (MONST_P
, OBJ_P
))) 0,
1149 (int FDECL((*), (OBJ_P
, OBJ_P
))) 0, &obj
);
1150 thrownobj
= obj
; /* obj may be null now */
1152 /* have to do this after bhit() so u.ux & u.uy are correct */
1153 if (Is_airlevel(&u
.uz
) || Levitation
)
1154 hurtle(-u
.dx
, -u
.dy
, urange
, TRUE
);
1163 if (mon
->isshk
&& obj
->where
== OBJ_MINVENT
&& obj
->ocarry
== mon
) {
1164 thrownobj
= (struct obj
*) 0;
1165 return; /* alert shk caught it */
1167 (void) snuff_candle(obj
);
1168 notonhead
= (bhitpos
.x
!= mon
->mx
|| bhitpos
.y
!= mon
->my
);
1169 obj_gone
= thitmonst(mon
, obj
);
1170 /* Monster may have been tamed; this frees old mon */
1171 mon
= m_at(bhitpos
.x
, bhitpos
.y
);
1173 /* [perhaps this should be moved into thitmonst or hmon] */
1174 if (mon
&& mon
->isshk
1175 && (!inside_shop(u
.ux
, u
.uy
)
1176 || !index(in_rooms(mon
->mx
, mon
->my
, SHOPBASE
), *u
.ushops
)))
1184 ; /* missile has already been handled */
1185 } else if (u
.uswallow
) {
1186 /* ball is not picked up by monster */
1188 (void) mpickobj(u
.ustuck
, obj
);
1189 thrownobj
= (struct obj
*) 0;
1191 /* the code following might become part of dropy() */
1192 if (obj
->oartifact
== ART_MJOLLNIR
&& Role_if(PM_VALKYRIE
)
1194 /* we must be wearing Gauntlets of Power to get here */
1195 sho_obj_return_to_u(obj
); /* display its flight */
1197 if (!impaired
&& rn2(100)) {
1198 pline("%s to your hand!", Tobjnam(obj
, "return"));
1200 (void) encumber_msg();
1202 u
.twoweap
= twoweap
;
1203 if (cansee(bhitpos
.x
, bhitpos
.y
))
1204 newsym(bhitpos
.x
, bhitpos
.y
);
1208 pline(Blind
? "%s lands %s your %s."
1209 : "%s back to you, landing %s your %s.",
1210 Blind
? Something
: Tobjnam(obj
, "return"),
1211 Levitation
? "beneath" : "at",
1212 makeplural(body_part(FOOT
)));
1215 pline(Blind
? "%s your %s!"
1216 : "%s back toward you, hitting your %s!",
1217 Tobjnam(obj
, Blind
? "hit" : "fly"),
1219 (void) artifact_hit((struct monst
*) 0, &youmonst
, obj
,
1221 losehp(Maybe_Half_Phys(dmg
), killer_xname(obj
),
1224 if (ship_object(obj
, u
.ux
, u
.uy
, FALSE
)) {
1225 thrownobj
= (struct obj
*) 0;
1230 thrownobj
= (struct obj
*) 0;
1234 if (!IS_SOFT(levl
[bhitpos
.x
][bhitpos
.y
].typ
) && breaktest(obj
)) {
1235 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
1236 tmp_at(bhitpos
.x
, bhitpos
.y
);
1238 tmp_at(DISP_END
, 0);
1239 breakmsg(obj
, cansee(bhitpos
.x
, bhitpos
.y
));
1240 breakobj(obj
, bhitpos
.x
, bhitpos
.y
, TRUE
, TRUE
);
1241 thrownobj
= (struct obj
*) 0;
1244 if (flooreffects(obj
, bhitpos
.x
, bhitpos
.y
, "fall")) {
1245 thrownobj
= (struct obj
*) 0;
1248 obj_no_longer_held(obj
);
1249 if (mon
&& mon
->isshk
&& is_pick(obj
)) {
1250 if (cansee(bhitpos
.x
, bhitpos
.y
))
1251 pline("%s snatches up %s.", Monnam(mon
), the(xname(obj
)));
1252 if (*u
.ushops
|| obj
->unpaid
)
1253 check_shop_obj(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
);
1254 (void) mpickobj(mon
, obj
); /* may merge and free obj */
1255 thrownobj
= (struct obj
*) 0;
1258 (void) snuff_candle(obj
);
1259 if (!mon
&& ship_object(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
)) {
1260 thrownobj
= (struct obj
*) 0;
1263 thrownobj
= (struct obj
*) 0;
1264 place_object(obj
, bhitpos
.x
, bhitpos
.y
);
1265 /* container contents might break;
1266 do so before turning ownership of thrownobj over to shk
1267 (container_impact_dmg handles item already owned by shop) */
1268 if (!IS_SOFT(levl
[bhitpos
.x
][bhitpos
.y
].typ
))
1269 /* <x,y> is spot where you initiated throw, not bhitpos */
1270 container_impact_dmg(obj
, u
.ux
, u
.uy
);
1271 /* charge for items thrown out of shop;
1272 shk takes possession for items thrown into one */
1273 if ((*u
.ushops
|| obj
->unpaid
) && obj
!= uball
)
1274 check_shop_obj(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
);
1278 drop_ball(bhitpos
.x
, bhitpos
.y
);
1279 if (cansee(bhitpos
.x
, bhitpos
.y
))
1280 newsym(bhitpos
.x
, bhitpos
.y
);
1281 if (obj_sheds_light(obj
))
1282 vision_full_recalc
= 1;
1286 /* an object may hit a monster; various factors adjust the chance of hitting
1289 omon_adj(mon
, obj
, mon_notices
)
1292 boolean mon_notices
;
1296 /* size of target affects the chance of hitting */
1297 tmp
+= (mon
->data
->msize
- MZ_MEDIUM
); /* -2..+5 */
1298 /* sleeping target is more likely to be hit */
1299 if (mon
->msleeping
) {
1304 /* ditto for immobilized target */
1305 if (!mon
->mcanmove
|| !mon
->data
->mmove
) {
1307 if (mon_notices
&& mon
->data
->mmove
&& !rn2(10)) {
1312 /* some objects are more likely to hit than others */
1313 switch (obj
->otyp
) {
1314 case HEAVY_IRON_BALL
:
1322 if (obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)
1323 || obj
->oclass
== GEM_CLASS
)
1324 tmp
+= hitval(obj
, mon
);
1330 /* thrown object misses target monster */
1332 tmiss(obj
, mon
, maybe_wakeup
)
1335 boolean maybe_wakeup
;
1337 const char *missile
= mshot_xname(obj
);
1339 /* If the target can't be seen or doesn't look like a valid target,
1340 avoid "the arrow misses it," or worse, "the arrows misses the mimic."
1341 An attentive player will still notice that this is different from
1342 an arrow just landing short of any target (no message in that case),
1343 so will realize that there is a valid target here anyway. */
1344 if (!canseemon(mon
) || (mon
->m_ap_type
&& mon
->m_ap_type
!= M_AP_MONSTER
))
1345 pline("%s %s.", The(missile
), otense(obj
, "miss"));
1348 if (maybe_wakeup
&& !rn2(3))
1353 #define quest_arti_hits_leader(obj, mon) \
1354 (obj->oartifact && is_quest_artifact(obj) \
1355 && mon->m_id == quest_status.leader_m_id)
1358 * Object thrown by player arrives at monster's location.
1359 * Return 1 if obj has disappeared or otherwise been taken care of,
1360 * 0 if caller must take care of it.
1361 * Also used for kicked objects and for polearms/grapnel applied at range.
1365 register struct monst
*mon
;
1366 register struct obj
*obj
; /* thrownobj or kickedobj or uwep */
1368 register int tmp
; /* Base chance to hit */
1369 register int disttmp
; /* distance modifier */
1370 int otyp
= obj
->otyp
, hmode
;
1371 boolean guaranteed_hit
= (u
.uswallow
&& mon
== u
.ustuck
);
1373 hmode
= (obj
== uwep
) ? HMON_APPLIED
1374 : (obj
== kickedobj
) ? HMON_KICKED
1377 /* Differences from melee weapons:
1379 * Dex still gives a bonus, but strength does not.
1380 * Polymorphed players lacking attacks may still throw.
1381 * There's a base -1 to hit.
1382 * No bonuses for fleeing or stunned targets (they don't dodge
1383 * melee blows as readily, but dodging arrows is hard anyway).
1384 * Not affected by traps, etc.
1385 * Certain items which don't in themselves do damage ignore tmp.
1386 * Distance and monster size affect chance to hit.
1388 tmp
= -1 + Luck
+ find_mac(mon
) + u
.uhitinc
1389 + maybe_polyd(youmonst
.data
->mlevel
, u
.ulevel
);
1390 if (ACURR(A_DEX
) < 4)
1392 else if (ACURR(A_DEX
) < 6)
1394 else if (ACURR(A_DEX
) < 8)
1396 else if (ACURR(A_DEX
) >= 14)
1397 tmp
+= (ACURR(A_DEX
) - 14);
1399 /* Modify to-hit depending on distance; but keep it sane.
1400 * Polearms get a distance penalty even when wielded; it's
1401 * hard to hit at a distance.
1403 disttmp
= 3 - distmin(u
.ux
, u
.uy
, mon
->mx
, mon
->my
);
1408 /* gloves are a hindrance to proper use of bows */
1409 if (uarmg
&& uwep
&& objects
[uwep
->otyp
].oc_skill
== P_BOW
) {
1410 switch (uarmg
->otyp
) {
1411 case GAUNTLETS_OF_POWER
: /* metal */
1414 case GAUNTLETS_OF_FUMBLING
:
1417 case LEATHER_GLOVES
:
1418 case GAUNTLETS_OF_DEXTERITY
:
1421 impossible("Unknown type of gloves (%d)", uarmg
->otyp
);
1426 tmp
+= omon_adj(mon
, obj
, TRUE
);
1427 if (is_orc(mon
->data
)
1428 && maybe_polyd(is_elf(youmonst
.data
), Race_if(PM_ELF
)))
1430 if (guaranteed_hit
) {
1431 tmp
+= 1000; /* Guaranteed hit */
1434 if (obj
->oclass
== GEM_CLASS
&& is_unicorn(mon
->data
)) {
1435 if (mon
->msleeping
|| !mon
->mcanmove
) {
1436 tmiss(obj
, mon
, FALSE
);
1438 } else if (mon
->mtame
) {
1439 pline("%s catches and drops %s.", Monnam(mon
), the(xname(obj
)));
1442 pline("%s catches %s.", Monnam(mon
), the(xname(obj
)));
1443 return gem_accept(mon
, obj
);
1447 /* don't make game unwinnable if naive player throws artifact
1448 at leader... (kicked artifact is ok too; HMON_APPLIED could
1449 occur if quest artifact polearm or grapnel ever gets added) */
1450 if (hmode
!= HMON_APPLIED
&& quest_arti_hits_leader(obj
, mon
)) {
1451 /* not wakeup(), which angers non-tame monsters */
1453 mon
->mstrategy
&= ~STRAT_WAITMASK
;
1455 if (mon
->mcanmove
) {
1456 pline("%s catches %s.", Monnam(mon
), the(xname(obj
)));
1457 if (mon
->mpeaceful
) {
1458 boolean next2u
= monnear(mon
, u
.ux
, u
.uy
);
1460 finish_quest(obj
); /* acknowledge quest completion */
1461 pline("%s %s %s back to you.", Monnam(mon
),
1462 (next2u
? "hands" : "tosses"), the(xname(obj
)));
1464 sho_obj_return_to_u(obj
);
1465 obj
= addinv(obj
); /* back into your inventory */
1466 (void) encumber_msg();
1468 /* angry leader caught it and isn't returning it */
1469 if (*u
.ushops
|| obj
->unpaid
) /* not very likely... */
1470 check_shop_obj(obj
, mon
->mx
, mon
->my
, FALSE
);
1471 (void) mpickobj(mon
, obj
);
1473 return 1; /* caller doesn't need to place it */
1478 if (obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)
1479 || obj
->oclass
== GEM_CLASS
) {
1480 if (hmode
== HMON_KICKED
) {
1481 /* throwing adjustments and weapon skill bonus don't apply */
1482 tmp
-= (is_ammo(obj
) ? 5 : 3);
1483 } else if (is_ammo(obj
)) {
1484 if (!ammo_and_launcher(obj
, uwep
)) {
1487 tmp
+= uwep
->spe
- greatest_erosion(uwep
);
1488 tmp
+= weapon_hit_bonus(uwep
);
1489 if (uwep
->oartifact
)
1490 tmp
+= spec_abon(uwep
, mon
);
1492 * Elves and Samurais are highly trained w/bows,
1493 * especially their own special types of bow.
1494 * Polymorphing won't make you a bow expert.
1496 if ((Race_if(PM_ELF
) || Role_if(PM_SAMURAI
))
1497 && (!Upolyd
|| your_race(youmonst
.data
))
1498 && objects
[uwep
->otyp
].oc_skill
== P_BOW
) {
1500 if (Race_if(PM_ELF
) && uwep
->otyp
== ELVEN_BOW
)
1502 else if (Role_if(PM_SAMURAI
) && uwep
->otyp
== YUMI
)
1506 } else { /* thrown non-ammo or applied polearm/grapnel */
1507 if (otyp
== BOOMERANG
) /* arbitrary */
1509 else if (throwing_weapon(obj
)) /* meant to be thrown */
1511 else if (obj
== thrownobj
) /* not meant to be thrown */
1513 /* we know we're dealing with a weapon or weptool handled
1514 by WEAPON_SKILLS once ammo objects have been excluded */
1515 tmp
+= weapon_hit_bonus(obj
);
1518 if (tmp
>= rnd(20)) {
1519 boolean wasthrown
= (thrownobj
!= 0);
1521 /* attack hits mon */
1522 if (hmode
== HMON_APPLIED
)
1523 u
.uconduct
.weaphit
++;
1524 if (hmon(mon
, obj
, hmode
)) { /* mon still alive */
1525 cutworm(mon
, bhitpos
.x
, bhitpos
.y
, obj
);
1527 exercise(A_DEX
, TRUE
);
1528 /* if hero was swallowed and projectile killed the engulfer,
1529 'obj' got added to engulfer's inventory and then dropped,
1530 so we can't safely use that pointer anymore; it escapes
1531 the chance to be used up here... */
1532 if (wasthrown
&& !thrownobj
)
1535 /* projectiles other than magic stones
1536 sometimes disappear when thrown */
1537 if (objects
[otyp
].oc_skill
< P_NONE
1538 && objects
[otyp
].oc_skill
> -P_BOOMERANG
1539 && !objects
[otyp
].oc_magic
) {
1540 /* we were breaking 2/3 of everything unconditionally.
1541 * we still don't want anything to survive unconditionally,
1542 * but we need ammo to stay around longer on average.
1546 chance
= 3 + greatest_erosion(obj
) - obj
->spe
;
1548 broken
= rn2(chance
);
1551 if (obj
->blessed
&& !rnl(4))
1555 if (*u
.ushops
|| obj
->unpaid
)
1556 check_shop_obj(obj
, bhitpos
.x
, bhitpos
.y
, TRUE
);
1557 obfree(obj
, (struct obj
*) 0);
1561 passive_obj(mon
, obj
, (struct attack
*) 0);
1563 tmiss(obj
, mon
, TRUE
);
1564 if (hmode
== HMON_APPLIED
)
1568 } else if (otyp
== HEAVY_IRON_BALL
) {
1569 exercise(A_STR
, TRUE
);
1570 if (tmp
>= rnd(20)) {
1571 int was_swallowed
= guaranteed_hit
;
1573 exercise(A_DEX
, TRUE
);
1574 if (!hmon(mon
, obj
, hmode
)) { /* mon killed */
1575 if (was_swallowed
&& !u
.uswallow
&& obj
== uball
)
1576 return 1; /* already did placebc() */
1579 tmiss(obj
, mon
, TRUE
);
1582 } else if (otyp
== BOULDER
) {
1583 exercise(A_STR
, TRUE
);
1584 if (tmp
>= rnd(20)) {
1585 exercise(A_DEX
, TRUE
);
1586 (void) hmon(mon
, obj
, hmode
);
1588 tmiss(obj
, mon
, TRUE
);
1591 } else if ((otyp
== EGG
|| otyp
== CREAM_PIE
|| otyp
== BLINDING_VENOM
1592 || otyp
== ACID_VENOM
)
1593 && (guaranteed_hit
|| ACURR(A_DEX
) > rnd(25))) {
1594 (void) hmon(mon
, obj
, hmode
);
1595 return 1; /* hmon used it up */
1597 } else if (obj
->oclass
== POTION_CLASS
1598 && (guaranteed_hit
|| ACURR(A_DEX
) > rnd(25))) {
1599 potionhit(mon
, obj
, TRUE
);
1602 } else if (befriend_with_obj(mon
->data
, obj
)
1603 || (mon
->mtame
&& dogfood(mon
, obj
) <= ACCFOOD
)) {
1604 if (tamedog(mon
, obj
)) {
1605 return 1; /* obj is gone */
1607 tmiss(obj
, mon
, FALSE
);
1609 mon
->mstrategy
&= ~STRAT_WAITMASK
;
1611 } else if (guaranteed_hit
) {
1612 /* this assumes that guaranteed_hit is due to swallowing */
1614 if (obj
->otyp
== CORPSE
&& touch_petrifies(&mons
[obj
->corpsenm
])) {
1615 if (is_animal(u
.ustuck
->data
)) {
1616 minstapetrify(u
.ustuck
, TRUE
);
1617 /* Don't leave a cockatrice corpse available in a statue */
1624 pline("%s into %s %s.", Tobjnam(obj
, "vanish"),
1625 s_suffix(mon_nam(mon
)),
1626 is_animal(u
.ustuck
->data
) ? "entrails" : "currents");
1628 tmiss(obj
, mon
, TRUE
);
1635 gem_accept(mon
, obj
)
1636 register struct monst
*mon
;
1637 register struct obj
*obj
;
1640 boolean is_buddy
= sgn(mon
->data
->maligntyp
) == sgn(u
.ualign
.type
);
1641 boolean is_gem
= objects
[obj
->otyp
].oc_material
== GEMSTONE
;
1643 static NEARDATA
const char nogood
[] = " is not interested in your junk.";
1644 static NEARDATA
const char acceptgift
[] = " accepts your gift.";
1645 static NEARDATA
const char maybeluck
[] = " hesitatingly";
1646 static NEARDATA
const char noluck
[] = " graciously";
1647 static NEARDATA
const char addluck
[] = " gratefully";
1649 Strcpy(buf
, Monnam(mon
));
1653 /* object properly identified */
1654 if (obj
->dknown
&& objects
[obj
->otyp
].oc_name_known
) {
1657 Strcat(buf
, addluck
);
1660 Strcat(buf
, maybeluck
);
1661 change_luck(rn2(7) - 3);
1664 Strcat(buf
, nogood
);
1667 /* making guesses */
1668 } else if (has_oname(obj
) || objects
[obj
->otyp
].oc_uname
) {
1671 Strcat(buf
, addluck
);
1674 Strcat(buf
, maybeluck
);
1675 change_luck(rn2(3) - 1);
1678 Strcat(buf
, nogood
);
1681 /* value completely unknown to @ */
1685 Strcat(buf
, addluck
);
1688 Strcat(buf
, maybeluck
);
1689 change_luck(rn2(3) - 1);
1692 Strcat(buf
, noluck
);
1695 Strcat(buf
, acceptgift
);
1696 if (*u
.ushops
|| obj
->unpaid
)
1697 check_shop_obj(obj
, mon
->mx
, mon
->my
, TRUE
);
1698 (void) mpickobj(mon
, obj
); /* may merge and free obj */
1704 if (!tele_restrict(mon
))
1705 (void) rloc(mon
, TRUE
);
1710 * Comments about the restructuring of the old breaks() routine.
1712 * There are now three distinct phases to object breaking:
1713 * breaktest() - which makes the check/decision about whether the
1714 * object is going to break.
1715 * breakmsg() - which outputs a message about the breakage,
1716 * appropriate for that particular object. Should
1717 * only be called after a positive breaktest().
1718 * on the object and, if it going to be called,
1719 * it must be called before calling breakobj().
1720 * Calling breakmsg() is optional.
1721 * breakobj() - which actually does the breakage and the side-effects
1722 * of breaking that particular object. This should
1723 * only be called after a positive breaktest() on the
1726 * Each of the above routines is currently static to this source module.
1727 * There are two routines callable from outside this source module which
1728 * perform the routines above in the correct sequence.
1730 * hero_breaks() - called when an object is to be broken as a result
1731 * of something that the hero has done. (throwing it,
1733 * breaks() - called when an object is to be broken for some
1734 * reason other than the hero doing something to it.
1738 * The hero causes breakage of an object (throwing, dropping it, etc.)
1739 * Return 0 if the object didn't break, 1 if the object broke.
1742 hero_breaks(obj
, x
, y
, from_invent
)
1744 xchar x
, y
; /* object location (ox, oy may not be right) */
1745 boolean from_invent
; /* thrown or dropped by player; maybe on shop bill */
1747 boolean in_view
= Blind
? FALSE
: (from_invent
|| cansee(x
, y
));
1748 if (!breaktest(obj
))
1750 breakmsg(obj
, in_view
);
1751 breakobj(obj
, x
, y
, TRUE
, from_invent
);
1756 * The object is going to break for a reason other than the hero doing
1758 * Return 0 if the object doesn't break, 1 if the object broke.
1763 xchar x
, y
; /* object location (ox, oy may not be right) */
1765 boolean in_view
= Blind
? FALSE
: cansee(x
, y
);
1767 if (!breaktest(obj
))
1769 breakmsg(obj
, in_view
);
1770 breakobj(obj
, x
, y
, FALSE
, FALSE
);
1775 release_camera_demon(obj
, x
, y
)
1781 && (mtmp
= makemon(&mons
[rn2(3) ? PM_HOMUNCULUS
: PM_IMP
], x
, y
,
1782 NO_MM_FLAGS
)) != 0) {
1783 if (canspotmon(mtmp
))
1784 pline("%s is released!", Hallucination
1785 ? An(rndmonnam(NULL
))
1786 : "The picture-painting demon");
1787 mtmp
->mpeaceful
= !obj
->cursed
;
1793 * Unconditionally break an object. Assumes all resistance checks
1794 * and break messages have been delivered prior to getting here.
1797 breakobj(obj
, x
, y
, hero_caused
, from_invent
)
1799 xchar x
, y
; /* object location (ox, oy may not be right) */
1800 boolean hero_caused
; /* is this the hero's fault? */
1801 boolean from_invent
;
1803 boolean fracture
= FALSE
;
1805 switch (obj
->oclass
== POTION_CLASS
? POT_WATER
: obj
->otyp
) {
1810 case POT_WATER
: /* really, all potions */
1811 obj
->in_use
= 1; /* in case it's fatal */
1812 if (obj
->otyp
== POT_OIL
&& obj
->lamplit
) {
1813 explode_oil(obj
, x
, y
);
1814 } else if (distu(x
, y
) <= 2) {
1815 if (!breathless(youmonst
.data
) || haseyes(youmonst
.data
)) {
1816 if (obj
->otyp
!= POT_WATER
) {
1817 if (!breathless(youmonst
.data
)) {
1818 /* [what about "familiar odor" when known?] */
1819 You("smell a peculiar odor...");
1821 const char *eyes
= body_part(EYE
);
1823 if (eyecount(youmonst
.data
) != 1)
1824 eyes
= makeplural(eyes
);
1825 Your("%s %s.", eyes
, vtense(eyes
, "water"));
1831 /* monster breathing isn't handled... [yet?] */
1833 case EXPENSIVE_CAMERA
:
1834 release_camera_demon(obj
, x
, y
);
1837 /* breaking your own eggs is bad luck */
1838 if (hero_caused
&& obj
->spe
&& obj
->corpsenm
>= LOW_PM
)
1839 change_luck((schar
) -min(obj
->quan
, 5L));
1843 /* caller will handle object disposition;
1844 we're just doing the shop theft handling */
1852 if (from_invent
|| obj
->unpaid
) {
1853 if (*u
.ushops
|| obj
->unpaid
)
1854 check_shop_obj(obj
, x
, y
, TRUE
);
1855 } else if (!obj
->no_charge
&& costly_spot(x
, y
)) {
1856 /* it is assumed that the obj is a floor-object */
1857 char *o_shop
= in_rooms(x
, y
, SHOPBASE
);
1858 struct monst
*shkp
= shop_keeper(*o_shop
);
1860 if (shkp
) { /* (implies *o_shop != '\0') */
1861 static NEARDATA
long lastmovetime
= 0L;
1862 static NEARDATA boolean peaceful_shk
= FALSE
;
1863 /* We want to base shk actions on her peacefulness
1864 at start of this turn, so that "simultaneous"
1865 multiple breakage isn't drastically worse than
1866 single breakage. (ought to be done via ESHK) */
1867 if (moves
!= lastmovetime
)
1868 peaceful_shk
= shkp
->mpeaceful
;
1869 if (stolen_value(obj
, x
, y
, peaceful_shk
, FALSE
) > 0L
1870 && (*o_shop
!= u
.ushops
[0] || !inside_shop(u
.ux
, u
.uy
))
1871 && moves
!= lastmovetime
)
1872 make_angry_shk(shkp
, x
, y
);
1873 lastmovetime
= moves
;
1882 * Check to see if obj is going to break, but don't actually break it.
1883 * Return 0 if the object isn't going to break, 1 if it is.
1889 if (obj_resists(obj
, 1, 99))
1891 if (objects
[obj
->otyp
].oc_material
== GLASS
&& !obj
->oartifact
1892 && obj
->oclass
!= GEM_CLASS
)
1894 switch (obj
->oclass
== POTION_CLASS
? POT_WATER
: obj
->otyp
) {
1895 case EXPENSIVE_CAMERA
:
1896 case POT_WATER
: /* really, all potions */
1901 case BLINDING_VENOM
:
1909 breakmsg(obj
, in_view
)
1913 const char *to_pieces
;
1916 switch (obj
->oclass
== POTION_CLASS
? POT_WATER
: obj
->otyp
) {
1917 default: /* glass or crystal wand */
1918 if (obj
->oclass
!= WAND_CLASS
)
1919 impossible("breaking odd object?");
1920 case CRYSTAL_PLATE_MAIL
:
1924 case EXPENSIVE_CAMERA
:
1925 to_pieces
= " into a thousand pieces";
1927 case POT_WATER
: /* really, all potions */
1929 You_hear("%s shatter!", something
);
1931 pline("%s shatter%s%s!", Doname2(obj
),
1932 (obj
->quan
== 1L) ? "s" : "", to_pieces
);
1940 pline("What a mess!");
1943 case BLINDING_VENOM
:
1953 int range
, odx
, ody
;
1954 register struct monst
*mon
;
1956 if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
1957 You("cannot throw gold at yourself.");
1962 pline(is_animal(u
.ustuck
->data
) ? "%s in the %s's entrails."
1964 "The money disappears", mon_nam(u
.ustuck
));
1965 add_to_minv(u
.ustuck
, obj
);
1970 if (u
.dz
< 0 && !Is_airlevel(&u
.uz
) && !Underwater
1971 && !Is_waterlevel(&u
.uz
)) {
1972 pline_The("gold hits the %s, then falls back on top of your %s.",
1973 ceiling(u
.ux
, u
.uy
), body_part(HEAD
));
1974 /* some self damage? */
1976 pline("Fortunately, you are wearing %s!",
1977 an(helm_simple_name(uarmh
)));
1982 /* consistent with range for normal objects */
1983 range
= (int) ((ACURRSTR
) / 2 - obj
->owt
/ 40);
1985 /* see if the gold has a place to move into */
1988 if (!ZAP_POS(levl
[odx
][ody
].typ
) || closed_door(odx
, ody
)) {
1992 mon
= bhit(u
.dx
, u
.dy
, range
, THROWN_WEAPON
,
1993 (int FDECL((*), (MONST_P
, OBJ_P
))) 0,
1994 (int FDECL((*), (OBJ_P
, OBJ_P
))) 0, &obj
);
1996 return 1; /* object is gone */
1998 if (ghitm(mon
, obj
)) /* was it caught? */
2001 if (ship_object(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
))
2007 if (flooreffects(obj
, bhitpos
.x
, bhitpos
.y
, "fall"))
2010 pline_The("gold hits the %s.", surface(bhitpos
.x
, bhitpos
.y
));
2011 place_object(obj
, bhitpos
.x
, bhitpos
.y
);
2013 sellobj(obj
, bhitpos
.x
, bhitpos
.y
);
2015 newsym(bhitpos
.x
, bhitpos
.y
);