1 /* NetHack 3.6 dothrow.c $ANH-Date: 1455140444 2016/02/10 21:40:44 $ $ANH-Branch: master $:$ANH-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 setmangry(mon
, FALSE
);
613 wake_nearto(x
,y
, 10);
616 if ((u
.ux
- x
) && (u
.uy
- y
) && bad_rock(youmonst
.data
, u
.ux
, y
)
617 && bad_rock(youmonst
.data
, x
, u
.uy
)) {
618 /* Move at a diagonal. */
620 You("come to an abrupt halt!");
625 /* Caller has already determined that dragging the ball is allowed */
626 if (Punished
&& uball
->where
== OBJ_FLOOR
) {
628 xchar ballx
, bally
, chainx
, chainy
;
631 if (drag_ball(x
, y
, &bc_control
, &ballx
, &bally
, &chainx
,
632 &chainy
, &cause_delay
, TRUE
))
633 move_bc(0, bc_control
, ballx
, bally
, chainx
, chainy
);
638 u_on_newpos(x
, y
); /* set u.<ux,uy>, u.usteed-><mx,my>; cliparound(); */
639 newsym(ox
, oy
); /* update old position */
640 vision_recalc(1); /* update for new position */
643 if (levl
[x
][y
].typ
== WATER
&& Is_waterlevel(&u
.uz
)) {
650 * Each trap should really trigger on the recoil if
651 * it would trigger during normal movement. However,
652 * not all the possible side-effects of this are
653 * tested [as of 3.4.0] so we trigger those that
654 * we have tested, and offer a message for the
655 * ones that we have not yet tested.
657 if ((ttmp
= t_at(x
, y
)) != 0) {
658 if (ttmp
->ttyp
== MAGIC_PORTAL
) {
661 } else if (ttmp
->ttyp
== VIBRATING_SQUARE
) {
662 pline("The ground vibrates as you pass it.");
663 dotrap(ttmp
, 0); /* doesn't print messages */
664 } else if (ttmp
->ttyp
== FIRE_TRAP
) {
666 } else if ((ttmp
->ttyp
== PIT
|| ttmp
->ttyp
== SPIKED_PIT
667 || ttmp
->ttyp
== HOLE
|| ttmp
->ttyp
== TRAPDOOR
)
669 /* Air currents overcome the recoil */
675 You("pass right over %s.",
676 an(defsyms
[trap_to_defsym(ttmp
->ttyp
)].explanation
));
679 if (--*range
< 0) /* make sure our range never goes negative */
687 mhurtle_step(arg
, x
, y
)
691 struct monst
*mon
= (struct monst
*) arg
;
693 /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially
694 * rather than just stopping before.
696 if (goodpos(x
, y
, mon
, 0) && m_in_out_region(mon
, x
, y
)) {
697 remove_monster(mon
->mx
, mon
->my
);
698 newsym(mon
->mx
, mon
->my
);
699 place_monster(mon
, x
, y
);
700 newsym(mon
->mx
, mon
->my
);
709 * The player moves through the air for a few squares as a result of
710 * throwing or kicking something.
712 * dx and dy should be the direction of the hurtle, not of the original
713 * kick or throw and be only.
716 hurtle(dx
, dy
, range
, verbose
)
722 /* The chain is stretched vertically, so you shouldn't be able to move
723 * very far diagonally. The premise that you should be able to move one
724 * spot leads to calculations that allow you to only move one spot away
725 * from the ball, if you are levitating over the ball, or one spot
726 * towards the ball, if you are at the end of the chain. Rather than
727 * bother with all of that, assume that there is no slack in the chain
728 * for diagonal movement, give the player a message and return.
730 if (Punished
&& !carried(uball
)) {
731 You_feel("a tug from the iron ball.");
734 } else if (u
.utrap
) {
735 You("are anchored by the %s.",
736 u
.utraptype
== TT_WEB
738 : u
.utraptype
== TT_LAVA
740 : u
.utraptype
== TT_INFLOOR
741 ? surface(u
.ux
, u
.uy
)
742 : u
.utraptype
== TT_BURIEDBALL
? "buried ball"
748 /* make sure dx and dy are [-1,0,1] */
752 if (!range
|| (!dx
&& !dy
) || u
.ustuck
)
753 return; /* paranoia */
756 multi_reason
= "moving through the air";
757 nomovemsg
= ""; /* it just happens */
759 You("%s in the opposite direction.", range
> 1 ? "hurtle" : "float");
760 /* if we're in the midst of shooting multiple projectiles, stop */
765 /* this setting of cc is only correct if dx and dy are [-1,0,1] only */
766 cc
.x
= u
.ux
+ (dx
* range
);
767 cc
.y
= u
.uy
+ (dy
* range
);
768 (void) walk_path(&uc
, &cc
, hurtle_step
, (genericptr_t
) &range
);
771 /* Move a monster through the air for a few squares.
774 mhurtle(mon
, dx
, dy
, range
)
780 /* At the very least, debilitate the monster */
784 /* Is the monster stuck or too heavy to push?
785 * (very large monsters have too much inertia, even floaters and flyers)
787 if (mon
->data
->msize
>= MZ_HUGE
|| mon
== u
.ustuck
|| mon
->mtrapped
)
790 /* Make sure dx and dy are [-1,0,1] */
793 if (!range
|| (!dx
&& !dy
))
794 return; /* paranoia */
795 /* don't let grid bugs be hurtled diagonally */
796 if (dx
&& dy
&& NODIAG(monsndx(mon
->data
)))
799 /* Send the monster along the path */
802 cc
.x
= mon
->mx
+ (dx
* range
);
803 cc
.y
= mon
->my
+ (dy
* range
);
804 (void) walk_path(&mc
, &cc
, mhurtle_step
, (genericptr_t
) mon
);
809 check_shop_obj(obj
, x
, y
, broken
)
814 struct monst
*shkp
= shop_keeper(*u
.ushops
);
819 if (broken
|| !costly_spot(x
, y
)
820 || *in_rooms(x
, y
, SHOPBASE
) != *u
.ushops
) {
821 /* thrown out of a shop or into a different shop */
823 (void) stolen_value(obj
, u
.ux
, u
.uy
, (boolean
) shkp
->mpeaceful
,
828 if (costly_spot(u
.ux
, u
.uy
) && costly_spot(x
, y
)) {
830 subfrombill(obj
, shkp
);
831 else if (x
!= shkp
->mx
|| y
!= shkp
->my
)
838 * Hero tosses an object upwards with appropriate consequences.
840 * Returns FALSE if the object is gone.
843 toss_up(obj
, hitsroof
)
848 boolean petrifier
= ((obj
->otyp
== EGG
|| obj
->otyp
== CORPSE
)
849 && touch_petrifies(&mons
[obj
->corpsenm
]));
850 /* note: obj->quan == 1 */
852 if (!has_ceiling(&u
.uz
)) {
853 action
= "flies up into"; /* into "the sky" or "the water above" */
854 } else if (hitsroof
) {
855 if (breaktest(obj
)) {
856 pline("%s hits the %s.", Doname2(obj
), ceiling(u
.ux
, u
.uy
));
857 breakmsg(obj
, !Blind
);
858 breakobj(obj
, u
.ux
, u
.uy
, TRUE
, TRUE
);
863 action
= "almost hits";
865 pline("%s %s the %s, then falls back on top of your %s.", Doname2(obj
),
866 action
, ceiling(u
.ux
, u
.uy
), body_part(HEAD
));
868 /* object now hits you */
870 if (obj
->oclass
== POTION_CLASS
) {
871 potionhit(&youmonst
, obj
, TRUE
);
872 } else if (breaktest(obj
)) {
873 int otyp
= obj
->otyp
;
876 /* need to check for blindness result prior to destroying obj */
877 blindinc
= ((otyp
== CREAM_PIE
|| otyp
== BLINDING_VENOM
)
878 /* AT_WEAP is ok here even if attack type was AT_SPIT */
879 && can_blnd(&youmonst
, &youmonst
, AT_WEAP
, obj
))
882 breakmsg(obj
, !Blind
);
883 breakobj(obj
, u
.ux
, u
.uy
, TRUE
, TRUE
);
884 obj
= 0; /* it's now gone */
887 if (petrifier
&& !Stone_resistance
888 && !(poly_when_stoned(youmonst
.data
)
889 && polymon(PM_STONE_GOLEM
))) {
890 /* egg ends up "all over your face"; perhaps
891 visored helmet should still save you here */
893 Your("%s fails to protect you.", helm_simple_name(uarmh
));
898 pline("You've got it all over your %s!", body_part(FACE
));
900 if (otyp
== BLINDING_VENOM
&& !Blind
)
901 pline("It blinds you!");
902 u
.ucreamed
+= blindinc
;
903 make_blinded(Blinded
+ (long) blindinc
, FALSE
);
905 Your1(vision_clears
);
912 } else { /* neither potion nor other breaking object */
913 boolean less_damage
= uarmh
&& is_metallic(uarmh
), artimsg
= FALSE
;
914 int dmg
= dmgval(obj
, &youmonst
);
917 /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */
918 artimsg
= artifact_hit((struct monst
*) 0, &youmonst
, obj
, &dmg
,
921 if (!dmg
) { /* probably wasn't a weapon; base damage on weight */
922 dmg
= (int) obj
->owt
/ 100;
927 if (youmonst
.data
== &mons
[PM_SHADE
]
928 && objects
[obj
->otyp
].oc_material
!= SILVER
)
931 if (dmg
> 1 && less_damage
)
936 dmg
= 0; /* beware negative rings of increase damage */
937 dmg
= Maybe_Half_Phys(dmg
);
940 if (less_damage
&& dmg
< (Upolyd
? u
.mh
: u
.uhp
)) {
942 pline("Fortunately, you are wearing a hard helmet.");
943 /* helmet definitely protects you when it blocks petrification
945 } else if (!petrifier
) {
947 Your("%s does not protect you.", helm_simple_name(uarmh
));
949 } else if (petrifier
&& !Stone_resistance
950 && !(poly_when_stoned(youmonst
.data
)
951 && polymon(PM_STONE_GOLEM
))) {
953 killer
.format
= KILLED_BY
;
954 Strcpy(killer
.name
, "elementary physics"); /* "what goes up..." */
955 You("turn to stone.");
957 dropy(obj
); /* bypass most of hitfloor() */
958 thrownobj
= 0; /* now either gone or on floor */
960 return obj
? TRUE
: FALSE
;
964 losehp(Maybe_Half_Phys(dmg
), "falling object", KILLED_BY_AN
);
969 /* return true for weapon meant to be thrown; excludes ammo */
974 return (boolean
) (is_missile(obj
) || is_spear(obj
)
975 /* daggers and knife (excludes scalpel) */
976 || (is_blade(obj
) && !is_sword(obj
)
977 && (objects
[obj
->otyp
].oc_dir
& PIERCE
))
978 /* special cases [might want to add AXE] */
979 || obj
->otyp
== WAR_HAMMER
|| obj
->otyp
== AKLYS
);
982 /* the currently thrown object is returning to you (not for boomerangs) */
984 sho_obj_return_to_u(obj
)
987 /* might already be our location (bounced off a wall) */
988 if ((u
.dx
|| u
.dy
) && (bhitpos
.x
!= u
.ux
|| bhitpos
.y
!= u
.uy
)) {
989 int x
= bhitpos
.x
- u
.dx
, y
= bhitpos
.y
- u
.dy
;
991 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
992 while (isok(x
,y
) && (x
!= u
.ux
|| y
!= u
.uy
)) {
1002 /* throw an object, NB: obj may be consumed in the process */
1004 throwit(obj
, wep_mask
, twoweap
)
1006 long wep_mask
; /* used to re-equip returning boomerang */
1008 twoweap
; /* used to restore twoweapon mode if wielded weapon returns */
1010 register struct monst
*mon
;
1011 register int range
, urange
;
1012 boolean crossbowing
, impaired
= (Confusion
|| Stunned
|| Blind
1013 || Hallucination
|| Fumbling
);
1015 notonhead
= FALSE
; /* reset potentially stale value */
1016 if ((obj
->cursed
|| obj
->greased
) && (u
.dx
|| u
.dy
) && !rn2(7)) {
1017 boolean slipok
= TRUE
;
1018 if (ammo_and_launcher(obj
, uwep
))
1019 pline("%s!", Tobjnam(obj
, "misfire"));
1021 /* only slip if it's greased or meant to be thrown */
1022 if (obj
->greased
|| throwing_weapon(obj
))
1023 /* BUG: this message is grammatically incorrect if obj has
1024 a plural name; greased gloves or boots for instance. */
1025 pline("%s as you throw it!", Tobjnam(obj
, "slip"));
1038 if ((u
.dx
|| u
.dy
|| (u
.dz
< 1))
1039 && calc_capacity((int) obj
->owt
) > SLT_ENCUMBER
1040 && (Upolyd
? (u
.mh
< 5 && u
.mh
!= u
.mhmax
)
1041 : (u
.uhp
< 10 && u
.uhp
!= u
.uhpmax
))
1042 && obj
->owt
> (unsigned) ((Upolyd
? u
.mh
: u
.uhp
) * 2)
1043 && !Is_airlevel(&u
.uz
)) {
1044 You("have so little stamina, %s drops from your grasp.",
1046 exercise(A_CON
, FALSE
);
1052 thrownobj
->was_thrown
= 1;
1056 bhitpos
.x
= mon
->mx
;
1057 bhitpos
.y
= mon
->my
;
1059 if (u
.dz
< 0 && Role_if(PM_VALKYRIE
) && obj
->oartifact
== ART_MJOLLNIR
1061 pline("%s the %s and returns to your hand!", Tobjnam(obj
, "hit"),
1062 ceiling(u
.ux
, u
.uy
));
1064 (void) encumber_msg();
1066 u
.twoweap
= twoweap
;
1067 } else if (u
.dz
< 0) {
1068 (void) toss_up(obj
, rn2(5) && !Underwater
);
1069 } else if (u
.dz
> 0 && u
.usteed
&& obj
->oclass
== POTION_CLASS
1071 /* alternative to prayer or wand of opening/spell of knock
1072 for dealing with cursed saddle: throw holy water > */
1073 potionhit(u
.usteed
, obj
, TRUE
);
1077 thrownobj
= (struct obj
*) 0;
1080 } else if (obj
->otyp
== BOOMERANG
&& !Underwater
) {
1081 if (Is_airlevel(&u
.uz
) || Levitation
)
1082 hurtle(-u
.dx
, -u
.dy
, 1, TRUE
);
1083 mon
= boomhit(obj
, u
.dx
, u
.dy
);
1084 if (mon
== &youmonst
) { /* the thing was caught */
1085 exercise(A_DEX
, TRUE
);
1087 (void) encumber_msg();
1088 if (wep_mask
&& !(obj
->owornmask
& wep_mask
)) {
1089 setworn(obj
, wep_mask
);
1090 u
.twoweap
= twoweap
;
1092 thrownobj
= (struct obj
*) 0;
1096 /* crossbow range is independent of strength */
1098 (ammo_and_launcher(obj
, uwep
) && weapon_type(uwep
) == P_CROSSBOW
);
1099 urange
= (crossbowing
? 18 : (int) ACURRSTR
) / 2;
1100 /* balls are easy to throw or at least roll;
1101 * also, this insures the maximum range of a ball is greater
1102 * than 1, so the effects from throwing attached balls are
1105 if (obj
->otyp
== HEAVY_IRON_BALL
)
1106 range
= urange
- (int) (obj
->owt
/ 100);
1108 range
= urange
- (int) (obj
->owt
/ 40);
1112 else if (range
>= 5)
1119 if (ammo_and_launcher(obj
, uwep
)) {
1124 } else if (obj
->oclass
!= GEM_CLASS
)
1128 if (Is_airlevel(&u
.uz
) || Levitation
) {
1129 /* action, reaction... */
1138 if (obj
->otyp
== BOULDER
)
1139 range
= 20; /* you must be giant */
1140 else if (obj
->oartifact
== ART_MJOLLNIR
)
1141 range
= (range
+ 1) / 2; /* it's heavy */
1142 else if (obj
== uball
&& u
.utrap
&& u
.utraptype
== TT_INFLOOR
)
1148 mon
= bhit(u
.dx
, u
.dy
, range
, THROWN_WEAPON
,
1149 (int FDECL((*), (MONST_P
, OBJ_P
))) 0,
1150 (int FDECL((*), (OBJ_P
, OBJ_P
))) 0, &obj
);
1151 thrownobj
= obj
; /* obj may be null now */
1153 /* have to do this after bhit() so u.ux & u.uy are correct */
1154 if (Is_airlevel(&u
.uz
) || Levitation
)
1155 hurtle(-u
.dx
, -u
.dy
, urange
, TRUE
);
1164 if (mon
->isshk
&& obj
->where
== OBJ_MINVENT
&& obj
->ocarry
== mon
) {
1165 thrownobj
= (struct obj
*) 0;
1166 return; /* alert shk caught it */
1168 (void) snuff_candle(obj
);
1169 notonhead
= (bhitpos
.x
!= mon
->mx
|| bhitpos
.y
!= mon
->my
);
1170 obj_gone
= thitmonst(mon
, obj
);
1171 /* Monster may have been tamed; this frees old mon */
1172 mon
= m_at(bhitpos
.x
, bhitpos
.y
);
1174 /* [perhaps this should be moved into thitmonst or hmon] */
1175 if (mon
&& mon
->isshk
1176 && (!inside_shop(u
.ux
, u
.uy
)
1177 || !index(in_rooms(mon
->mx
, mon
->my
, SHOPBASE
), *u
.ushops
)))
1185 ; /* missile has already been handled */
1186 } else if (u
.uswallow
) {
1187 /* ball is not picked up by monster */
1189 (void) mpickobj(u
.ustuck
, obj
);
1190 thrownobj
= (struct obj
*) 0;
1192 /* the code following might become part of dropy() */
1193 if (obj
->oartifact
== ART_MJOLLNIR
&& Role_if(PM_VALKYRIE
)
1195 /* we must be wearing Gauntlets of Power to get here */
1196 sho_obj_return_to_u(obj
); /* display its flight */
1198 if (!impaired
&& rn2(100)) {
1199 pline("%s to your hand!", Tobjnam(obj
, "return"));
1201 (void) encumber_msg();
1203 u
.twoweap
= twoweap
;
1204 if (cansee(bhitpos
.x
, bhitpos
.y
))
1205 newsym(bhitpos
.x
, bhitpos
.y
);
1209 pline(Blind
? "%s lands %s your %s."
1210 : "%s back to you, landing %s your %s.",
1211 Blind
? Something
: Tobjnam(obj
, "return"),
1212 Levitation
? "beneath" : "at",
1213 makeplural(body_part(FOOT
)));
1216 pline(Blind
? "%s your %s!"
1217 : "%s back toward you, hitting your %s!",
1218 Tobjnam(obj
, Blind
? "hit" : "fly"),
1220 (void) artifact_hit((struct monst
*) 0, &youmonst
, obj
,
1222 losehp(Maybe_Half_Phys(dmg
), killer_xname(obj
),
1225 if (ship_object(obj
, u
.ux
, u
.uy
, FALSE
)) {
1226 thrownobj
= (struct obj
*) 0;
1231 thrownobj
= (struct obj
*) 0;
1235 if (!IS_SOFT(levl
[bhitpos
.x
][bhitpos
.y
].typ
) && breaktest(obj
)) {
1236 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
1237 tmp_at(bhitpos
.x
, bhitpos
.y
);
1239 tmp_at(DISP_END
, 0);
1240 breakmsg(obj
, cansee(bhitpos
.x
, bhitpos
.y
));
1241 breakobj(obj
, bhitpos
.x
, bhitpos
.y
, TRUE
, TRUE
);
1242 thrownobj
= (struct obj
*) 0;
1245 if (flooreffects(obj
, bhitpos
.x
, bhitpos
.y
, "fall")) {
1246 thrownobj
= (struct obj
*) 0;
1249 obj_no_longer_held(obj
);
1250 if (mon
&& mon
->isshk
&& is_pick(obj
)) {
1251 if (cansee(bhitpos
.x
, bhitpos
.y
))
1252 pline("%s snatches up %s.", Monnam(mon
), the(xname(obj
)));
1253 if (*u
.ushops
|| obj
->unpaid
)
1254 check_shop_obj(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
);
1255 (void) mpickobj(mon
, obj
); /* may merge and free obj */
1256 thrownobj
= (struct obj
*) 0;
1259 (void) snuff_candle(obj
);
1260 if (!mon
&& ship_object(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
)) {
1261 thrownobj
= (struct obj
*) 0;
1264 thrownobj
= (struct obj
*) 0;
1265 place_object(obj
, bhitpos
.x
, bhitpos
.y
);
1266 /* container contents might break;
1267 do so before turning ownership of thrownobj over to shk
1268 (container_impact_dmg handles item already owned by shop) */
1269 if (!IS_SOFT(levl
[bhitpos
.x
][bhitpos
.y
].typ
))
1270 /* <x,y> is spot where you initiated throw, not bhitpos */
1271 container_impact_dmg(obj
, u
.ux
, u
.uy
);
1272 /* charge for items thrown out of shop;
1273 shk takes possession for items thrown into one */
1274 if ((*u
.ushops
|| obj
->unpaid
) && obj
!= uball
)
1275 check_shop_obj(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
);
1279 drop_ball(bhitpos
.x
, bhitpos
.y
);
1280 if (cansee(bhitpos
.x
, bhitpos
.y
))
1281 newsym(bhitpos
.x
, bhitpos
.y
);
1282 if (obj_sheds_light(obj
))
1283 vision_full_recalc
= 1;
1287 /* an object may hit a monster; various factors adjust the chance of hitting
1290 omon_adj(mon
, obj
, mon_notices
)
1293 boolean mon_notices
;
1297 /* size of target affects the chance of hitting */
1298 tmp
+= (mon
->data
->msize
- MZ_MEDIUM
); /* -2..+5 */
1299 /* sleeping target is more likely to be hit */
1300 if (mon
->msleeping
) {
1305 /* ditto for immobilized target */
1306 if (!mon
->mcanmove
|| !mon
->data
->mmove
) {
1308 if (mon_notices
&& mon
->data
->mmove
&& !rn2(10)) {
1313 /* some objects are more likely to hit than others */
1314 switch (obj
->otyp
) {
1315 case HEAVY_IRON_BALL
:
1323 if (obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)
1324 || obj
->oclass
== GEM_CLASS
)
1325 tmp
+= hitval(obj
, mon
);
1331 /* thrown object misses target monster */
1333 tmiss(obj
, mon
, maybe_wakeup
)
1336 boolean maybe_wakeup
;
1338 const char *missile
= mshot_xname(obj
);
1340 /* If the target can't be seen or doesn't look like a valid target,
1341 avoid "the arrow misses it," or worse, "the arrows misses the mimic."
1342 An attentive player will still notice that this is different from
1343 an arrow just landing short of any target (no message in that case),
1344 so will realize that there is a valid target here anyway. */
1345 if (!canseemon(mon
) || (mon
->m_ap_type
&& mon
->m_ap_type
!= M_AP_MONSTER
))
1346 pline("%s %s.", The(missile
), otense(obj
, "miss"));
1349 if (maybe_wakeup
&& !rn2(3))
1354 #define quest_arti_hits_leader(obj, mon) \
1355 (obj->oartifact && is_quest_artifact(obj) \
1356 && mon->m_id == quest_status.leader_m_id)
1359 * Object thrown by player arrives at monster's location.
1360 * Return 1 if obj has disappeared or otherwise been taken care of,
1361 * 0 if caller must take care of it.
1362 * Also used for kicked objects and for polearms/grapnel applied at range.
1366 register struct monst
*mon
;
1367 register struct obj
*obj
; /* thrownobj or kickedobj or uwep */
1369 register int tmp
; /* Base chance to hit */
1370 register int disttmp
; /* distance modifier */
1371 int otyp
= obj
->otyp
, hmode
;
1372 boolean guaranteed_hit
= (u
.uswallow
&& mon
== u
.ustuck
);
1374 hmode
= (obj
== uwep
) ? HMON_APPLIED
1375 : (obj
== kickedobj
) ? HMON_KICKED
1378 /* Differences from melee weapons:
1380 * Dex still gives a bonus, but strength does not.
1381 * Polymorphed players lacking attacks may still throw.
1382 * There's a base -1 to hit.
1383 * No bonuses for fleeing or stunned targets (they don't dodge
1384 * melee blows as readily, but dodging arrows is hard anyway).
1385 * Not affected by traps, etc.
1386 * Certain items which don't in themselves do damage ignore tmp.
1387 * Distance and monster size affect chance to hit.
1389 tmp
= -1 + Luck
+ find_mac(mon
) + u
.uhitinc
1390 + maybe_polyd(youmonst
.data
->mlevel
, u
.ulevel
);
1391 if (ACURR(A_DEX
) < 4)
1393 else if (ACURR(A_DEX
) < 6)
1395 else if (ACURR(A_DEX
) < 8)
1397 else if (ACURR(A_DEX
) >= 14)
1398 tmp
+= (ACURR(A_DEX
) - 14);
1400 /* Modify to-hit depending on distance; but keep it sane.
1401 * Polearms get a distance penalty even when wielded; it's
1402 * hard to hit at a distance.
1404 disttmp
= 3 - distmin(u
.ux
, u
.uy
, mon
->mx
, mon
->my
);
1409 /* gloves are a hindrance to proper use of bows */
1410 if (uarmg
&& uwep
&& objects
[uwep
->otyp
].oc_skill
== P_BOW
) {
1411 switch (uarmg
->otyp
) {
1412 case GAUNTLETS_OF_POWER
: /* metal */
1415 case GAUNTLETS_OF_FUMBLING
:
1418 case LEATHER_GLOVES
:
1419 case GAUNTLETS_OF_DEXTERITY
:
1422 impossible("Unknown type of gloves (%d)", uarmg
->otyp
);
1427 tmp
+= omon_adj(mon
, obj
, TRUE
);
1428 if (is_orc(mon
->data
)
1429 && maybe_polyd(is_elf(youmonst
.data
), Race_if(PM_ELF
)))
1431 if (guaranteed_hit
) {
1432 tmp
+= 1000; /* Guaranteed hit */
1435 if (obj
->oclass
== GEM_CLASS
&& is_unicorn(mon
->data
)) {
1436 if (mon
->msleeping
|| !mon
->mcanmove
) {
1437 tmiss(obj
, mon
, FALSE
);
1439 } else if (mon
->mtame
) {
1440 pline("%s catches and drops %s.", Monnam(mon
), the(xname(obj
)));
1443 pline("%s catches %s.", Monnam(mon
), the(xname(obj
)));
1444 return gem_accept(mon
, obj
);
1448 /* don't make game unwinnable if naive player throws artifact
1449 at leader... (kicked artifact is ok too; HMON_APPLIED could
1450 occur if quest artifact polearm or grapnel ever gets added) */
1451 if (hmode
!= HMON_APPLIED
&& quest_arti_hits_leader(obj
, mon
)) {
1452 /* AIS: changes to wakeup() means that it's now less inappropriate here
1453 than it used to be, but the manual version works just as well */
1455 mon
->mstrategy
&= ~STRAT_WAITMASK
;
1457 if (mon
->mcanmove
) {
1458 pline("%s catches %s.", Monnam(mon
), the(xname(obj
)));
1459 if (mon
->mpeaceful
) {
1460 boolean next2u
= monnear(mon
, u
.ux
, u
.uy
);
1462 finish_quest(obj
); /* acknowledge quest completion */
1463 pline("%s %s %s back to you.", Monnam(mon
),
1464 (next2u
? "hands" : "tosses"), the(xname(obj
)));
1466 sho_obj_return_to_u(obj
);
1467 obj
= addinv(obj
); /* back into your inventory */
1468 (void) encumber_msg();
1470 /* angry leader caught it and isn't returning it */
1471 if (*u
.ushops
|| obj
->unpaid
) /* not very likely... */
1472 check_shop_obj(obj
, mon
->mx
, mon
->my
, FALSE
);
1473 (void) mpickobj(mon
, obj
);
1475 return 1; /* caller doesn't need to place it */
1480 if (obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)
1481 || obj
->oclass
== GEM_CLASS
) {
1482 if (hmode
== HMON_KICKED
) {
1483 /* throwing adjustments and weapon skill bonus don't apply */
1484 tmp
-= (is_ammo(obj
) ? 5 : 3);
1485 } else if (is_ammo(obj
)) {
1486 if (!ammo_and_launcher(obj
, uwep
)) {
1489 tmp
+= uwep
->spe
- greatest_erosion(uwep
);
1490 tmp
+= weapon_hit_bonus(uwep
);
1491 if (uwep
->oartifact
)
1492 tmp
+= spec_abon(uwep
, mon
);
1494 * Elves and Samurais are highly trained w/bows,
1495 * especially their own special types of bow.
1496 * Polymorphing won't make you a bow expert.
1498 if ((Race_if(PM_ELF
) || Role_if(PM_SAMURAI
))
1499 && (!Upolyd
|| your_race(youmonst
.data
))
1500 && objects
[uwep
->otyp
].oc_skill
== P_BOW
) {
1502 if (Race_if(PM_ELF
) && uwep
->otyp
== ELVEN_BOW
)
1504 else if (Role_if(PM_SAMURAI
) && uwep
->otyp
== YUMI
)
1508 } else { /* thrown non-ammo or applied polearm/grapnel */
1509 if (otyp
== BOOMERANG
) /* arbitrary */
1511 else if (throwing_weapon(obj
)) /* meant to be thrown */
1513 else if (obj
== thrownobj
) /* not meant to be thrown */
1515 /* we know we're dealing with a weapon or weptool handled
1516 by WEAPON_SKILLS once ammo objects have been excluded */
1517 tmp
+= weapon_hit_bonus(obj
);
1520 if (tmp
>= rnd(20)) {
1521 boolean wasthrown
= (thrownobj
!= 0);
1523 /* attack hits mon */
1524 if (hmode
== HMON_APPLIED
)
1525 u
.uconduct
.weaphit
++;
1526 if (hmon(mon
, obj
, hmode
)) { /* mon still alive */
1527 cutworm(mon
, bhitpos
.x
, bhitpos
.y
, obj
);
1529 exercise(A_DEX
, TRUE
);
1530 /* if hero was swallowed and projectile killed the engulfer,
1531 'obj' got added to engulfer's inventory and then dropped,
1532 so we can't safely use that pointer anymore; it escapes
1533 the chance to be used up here... */
1534 if (wasthrown
&& !thrownobj
)
1537 /* projectiles other than magic stones
1538 sometimes disappear when thrown */
1539 if (objects
[otyp
].oc_skill
< P_NONE
1540 && objects
[otyp
].oc_skill
> -P_BOOMERANG
1541 && !objects
[otyp
].oc_magic
) {
1542 /* we were breaking 2/3 of everything unconditionally.
1543 * we still don't want anything to survive unconditionally,
1544 * but we need ammo to stay around longer on average.
1548 chance
= 3 + greatest_erosion(obj
) - obj
->spe
;
1550 broken
= rn2(chance
);
1553 if (obj
->blessed
&& !rnl(4))
1557 if (*u
.ushops
|| obj
->unpaid
)
1558 check_shop_obj(obj
, bhitpos
.x
, bhitpos
.y
, TRUE
);
1559 obfree(obj
, (struct obj
*) 0);
1563 passive_obj(mon
, obj
, (struct attack
*) 0);
1565 tmiss(obj
, mon
, TRUE
);
1566 if (hmode
== HMON_APPLIED
)
1570 } else if (otyp
== HEAVY_IRON_BALL
) {
1571 exercise(A_STR
, TRUE
);
1572 if (tmp
>= rnd(20)) {
1573 int was_swallowed
= guaranteed_hit
;
1575 exercise(A_DEX
, TRUE
);
1576 if (!hmon(mon
, obj
, hmode
)) { /* mon killed */
1577 if (was_swallowed
&& !u
.uswallow
&& obj
== uball
)
1578 return 1; /* already did placebc() */
1581 tmiss(obj
, mon
, TRUE
);
1584 } else if (otyp
== BOULDER
) {
1585 exercise(A_STR
, TRUE
);
1586 if (tmp
>= rnd(20)) {
1587 exercise(A_DEX
, TRUE
);
1588 (void) hmon(mon
, obj
, hmode
);
1590 tmiss(obj
, mon
, TRUE
);
1593 } else if ((otyp
== EGG
|| otyp
== CREAM_PIE
|| otyp
== BLINDING_VENOM
1594 || otyp
== ACID_VENOM
)
1595 && (guaranteed_hit
|| ACURR(A_DEX
) > rnd(25))) {
1596 (void) hmon(mon
, obj
, hmode
);
1597 return 1; /* hmon used it up */
1599 } else if (obj
->oclass
== POTION_CLASS
1600 && (guaranteed_hit
|| ACURR(A_DEX
) > rnd(25))) {
1601 potionhit(mon
, obj
, TRUE
);
1604 } else if (befriend_with_obj(mon
->data
, obj
)
1605 || (mon
->mtame
&& dogfood(mon
, obj
) <= ACCFOOD
)) {
1606 if (tamedog(mon
, obj
)) {
1607 return 1; /* obj is gone */
1609 tmiss(obj
, mon
, FALSE
);
1611 mon
->mstrategy
&= ~STRAT_WAITMASK
;
1613 } else if (guaranteed_hit
) {
1614 /* this assumes that guaranteed_hit is due to swallowing */
1616 if (obj
->otyp
== CORPSE
&& touch_petrifies(&mons
[obj
->corpsenm
])) {
1617 if (is_animal(u
.ustuck
->data
)) {
1618 minstapetrify(u
.ustuck
, TRUE
);
1619 /* Don't leave a cockatrice corpse available in a statue */
1626 pline("%s into %s %s.", Tobjnam(obj
, "vanish"),
1627 s_suffix(mon_nam(mon
)),
1628 is_animal(u
.ustuck
->data
) ? "entrails" : "currents");
1630 tmiss(obj
, mon
, TRUE
);
1637 gem_accept(mon
, obj
)
1638 register struct monst
*mon
;
1639 register struct obj
*obj
;
1642 boolean is_buddy
= sgn(mon
->data
->maligntyp
) == sgn(u
.ualign
.type
);
1643 boolean is_gem
= objects
[obj
->otyp
].oc_material
== GEMSTONE
;
1645 static NEARDATA
const char nogood
[] = " is not interested in your junk.";
1646 static NEARDATA
const char acceptgift
[] = " accepts your gift.";
1647 static NEARDATA
const char maybeluck
[] = " hesitatingly";
1648 static NEARDATA
const char noluck
[] = " graciously";
1649 static NEARDATA
const char addluck
[] = " gratefully";
1651 Strcpy(buf
, Monnam(mon
));
1655 /* object properly identified */
1656 if (obj
->dknown
&& objects
[obj
->otyp
].oc_name_known
) {
1659 Strcat(buf
, addluck
);
1662 Strcat(buf
, maybeluck
);
1663 change_luck(rn2(7) - 3);
1666 Strcat(buf
, nogood
);
1669 /* making guesses */
1670 } else if (has_oname(obj
) || objects
[obj
->otyp
].oc_uname
) {
1673 Strcat(buf
, addluck
);
1676 Strcat(buf
, maybeluck
);
1677 change_luck(rn2(3) - 1);
1680 Strcat(buf
, nogood
);
1683 /* value completely unknown to @ */
1687 Strcat(buf
, addluck
);
1690 Strcat(buf
, maybeluck
);
1691 change_luck(rn2(3) - 1);
1694 Strcat(buf
, noluck
);
1697 Strcat(buf
, acceptgift
);
1698 if (*u
.ushops
|| obj
->unpaid
)
1699 check_shop_obj(obj
, mon
->mx
, mon
->my
, TRUE
);
1700 (void) mpickobj(mon
, obj
); /* may merge and free obj */
1706 if (!tele_restrict(mon
))
1707 (void) rloc(mon
, TRUE
);
1712 * Comments about the restructuring of the old breaks() routine.
1714 * There are now three distinct phases to object breaking:
1715 * breaktest() - which makes the check/decision about whether the
1716 * object is going to break.
1717 * breakmsg() - which outputs a message about the breakage,
1718 * appropriate for that particular object. Should
1719 * only be called after a positive breaktest().
1720 * on the object and, if it going to be called,
1721 * it must be called before calling breakobj().
1722 * Calling breakmsg() is optional.
1723 * breakobj() - which actually does the breakage and the side-effects
1724 * of breaking that particular object. This should
1725 * only be called after a positive breaktest() on the
1728 * Each of the above routines is currently static to this source module.
1729 * There are two routines callable from outside this source module which
1730 * perform the routines above in the correct sequence.
1732 * hero_breaks() - called when an object is to be broken as a result
1733 * of something that the hero has done. (throwing it,
1735 * breaks() - called when an object is to be broken for some
1736 * reason other than the hero doing something to it.
1740 * The hero causes breakage of an object (throwing, dropping it, etc.)
1741 * Return 0 if the object didn't break, 1 if the object broke.
1744 hero_breaks(obj
, x
, y
, from_invent
)
1746 xchar x
, y
; /* object location (ox, oy may not be right) */
1747 boolean from_invent
; /* thrown or dropped by player; maybe on shop bill */
1749 boolean in_view
= Blind
? FALSE
: (from_invent
|| cansee(x
, y
));
1750 if (!breaktest(obj
))
1752 breakmsg(obj
, in_view
);
1753 breakobj(obj
, x
, y
, TRUE
, from_invent
);
1758 * The object is going to break for a reason other than the hero doing
1760 * Return 0 if the object doesn't break, 1 if the object broke.
1765 xchar x
, y
; /* object location (ox, oy may not be right) */
1767 boolean in_view
= Blind
? FALSE
: cansee(x
, y
);
1769 if (!breaktest(obj
))
1771 breakmsg(obj
, in_view
);
1772 breakobj(obj
, x
, y
, FALSE
, FALSE
);
1777 release_camera_demon(obj
, x
, y
)
1783 && (mtmp
= makemon(&mons
[rn2(3) ? PM_HOMUNCULUS
: PM_IMP
], x
, y
,
1784 NO_MM_FLAGS
)) != 0) {
1785 if (canspotmon(mtmp
))
1786 pline("%s is released!", Hallucination
1787 ? An(rndmonnam(NULL
))
1788 : "The picture-painting demon");
1789 mtmp
->mpeaceful
= !obj
->cursed
;
1795 * Unconditionally break an object. Assumes all resistance checks
1796 * and break messages have been delivered prior to getting here.
1799 breakobj(obj
, x
, y
, hero_caused
, from_invent
)
1801 xchar x
, y
; /* object location (ox, oy may not be right) */
1802 boolean hero_caused
; /* is this the hero's fault? */
1803 boolean from_invent
;
1805 boolean fracture
= FALSE
;
1807 switch (obj
->oclass
== POTION_CLASS
? POT_WATER
: obj
->otyp
) {
1812 case POT_WATER
: /* really, all potions */
1813 obj
->in_use
= 1; /* in case it's fatal */
1814 if (obj
->otyp
== POT_OIL
&& obj
->lamplit
) {
1815 explode_oil(obj
, x
, y
);
1816 } else if (distu(x
, y
) <= 2) {
1817 if (!breathless(youmonst
.data
) || haseyes(youmonst
.data
)) {
1818 if (obj
->otyp
!= POT_WATER
) {
1819 if (!breathless(youmonst
.data
)) {
1820 /* [what about "familiar odor" when known?] */
1821 You("smell a peculiar odor...");
1823 const char *eyes
= body_part(EYE
);
1825 if (eyecount(youmonst
.data
) != 1)
1826 eyes
= makeplural(eyes
);
1827 Your("%s %s.", eyes
, vtense(eyes
, "water"));
1833 /* monster breathing isn't handled... [yet?] */
1835 case EXPENSIVE_CAMERA
:
1836 release_camera_demon(obj
, x
, y
);
1839 /* breaking your own eggs is bad luck */
1840 if (hero_caused
&& obj
->spe
&& obj
->corpsenm
>= LOW_PM
)
1841 change_luck((schar
) -min(obj
->quan
, 5L));
1845 /* caller will handle object disposition;
1846 we're just doing the shop theft handling */
1854 if (from_invent
|| obj
->unpaid
) {
1855 if (*u
.ushops
|| obj
->unpaid
)
1856 check_shop_obj(obj
, x
, y
, TRUE
);
1857 } else if (!obj
->no_charge
&& costly_spot(x
, y
)) {
1858 /* it is assumed that the obj is a floor-object */
1859 char *o_shop
= in_rooms(x
, y
, SHOPBASE
);
1860 struct monst
*shkp
= shop_keeper(*o_shop
);
1862 if (shkp
) { /* (implies *o_shop != '\0') */
1863 static NEARDATA
long lastmovetime
= 0L;
1864 static NEARDATA boolean peaceful_shk
= FALSE
;
1865 /* We want to base shk actions on her peacefulness
1866 at start of this turn, so that "simultaneous"
1867 multiple breakage isn't drastically worse than
1868 single breakage. (ought to be done via ESHK) */
1869 if (moves
!= lastmovetime
)
1870 peaceful_shk
= shkp
->mpeaceful
;
1871 if (stolen_value(obj
, x
, y
, peaceful_shk
, FALSE
) > 0L
1872 && (*o_shop
!= u
.ushops
[0] || !inside_shop(u
.ux
, u
.uy
))
1873 && moves
!= lastmovetime
)
1874 make_angry_shk(shkp
, x
, y
);
1875 lastmovetime
= moves
;
1884 * Check to see if obj is going to break, but don't actually break it.
1885 * Return 0 if the object isn't going to break, 1 if it is.
1891 if (obj_resists(obj
, 1, 99))
1893 if (objects
[obj
->otyp
].oc_material
== GLASS
&& !obj
->oartifact
1894 && obj
->oclass
!= GEM_CLASS
)
1896 switch (obj
->oclass
== POTION_CLASS
? POT_WATER
: obj
->otyp
) {
1897 case EXPENSIVE_CAMERA
:
1898 case POT_WATER
: /* really, all potions */
1903 case BLINDING_VENOM
:
1911 breakmsg(obj
, in_view
)
1915 const char *to_pieces
;
1918 switch (obj
->oclass
== POTION_CLASS
? POT_WATER
: obj
->otyp
) {
1919 default: /* glass or crystal wand */
1920 if (obj
->oclass
!= WAND_CLASS
)
1921 impossible("breaking odd object?");
1922 case CRYSTAL_PLATE_MAIL
:
1926 case EXPENSIVE_CAMERA
:
1927 to_pieces
= " into a thousand pieces";
1929 case POT_WATER
: /* really, all potions */
1931 You_hear("%s shatter!", something
);
1933 pline("%s shatter%s%s!", Doname2(obj
),
1934 (obj
->quan
== 1L) ? "s" : "", to_pieces
);
1942 pline("What a mess!");
1945 case BLINDING_VENOM
:
1955 int range
, odx
, ody
;
1956 register struct monst
*mon
;
1958 if (!u
.dx
&& !u
.dy
&& !u
.dz
) {
1959 You("cannot throw gold at yourself.");
1964 pline(is_animal(u
.ustuck
->data
) ? "%s in the %s's entrails."
1966 "The money disappears", mon_nam(u
.ustuck
));
1967 add_to_minv(u
.ustuck
, obj
);
1972 if (u
.dz
< 0 && !Is_airlevel(&u
.uz
) && !Underwater
1973 && !Is_waterlevel(&u
.uz
)) {
1974 pline_The("gold hits the %s, then falls back on top of your %s.",
1975 ceiling(u
.ux
, u
.uy
), body_part(HEAD
));
1976 /* some self damage? */
1978 pline("Fortunately, you are wearing %s!",
1979 an(helm_simple_name(uarmh
)));
1984 /* consistent with range for normal objects */
1985 range
= (int) ((ACURRSTR
) / 2 - obj
->owt
/ 40);
1987 /* see if the gold has a place to move into */
1990 if (!ZAP_POS(levl
[odx
][ody
].typ
) || closed_door(odx
, ody
)) {
1994 mon
= bhit(u
.dx
, u
.dy
, range
, THROWN_WEAPON
,
1995 (int FDECL((*), (MONST_P
, OBJ_P
))) 0,
1996 (int FDECL((*), (OBJ_P
, OBJ_P
))) 0, &obj
);
1998 return 1; /* object is gone */
2000 if (ghitm(mon
, obj
)) /* was it caught? */
2003 if (ship_object(obj
, bhitpos
.x
, bhitpos
.y
, FALSE
))
2009 if (flooreffects(obj
, bhitpos
.x
, bhitpos
.y
, "fall"))
2012 pline_The("gold hits the %s.", surface(bhitpos
.x
, bhitpos
.y
));
2013 place_object(obj
, bhitpos
.x
, bhitpos
.y
);
2015 sellobj(obj
, bhitpos
.x
, bhitpos
.y
);
2017 newsym(bhitpos
.x
, bhitpos
.y
);