1 /* NetHack 3.6 dokick.c $NHDT-Date: 1446955295 2015/11/08 04:01:35 $ $NHDT-Branch: master $:$NHDT-Revision: 1.104 $ */
2 /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
3 /* NetHack may be freely redistributed. See license for details. */
7 #define is_bigfoot(x) ((x) == &mons[PM_SASQUATCH])
9 (martial_bonus() || is_bigfoot(youmonst.data) \
10 || (uarmf && uarmf->otyp == KICKING_BOOTS))
12 static NEARDATA
struct rm
*maploc
, nowhere
;
13 static NEARDATA
const char *gate_str
;
15 /* kickedobj (decl.c) tracks a kicked object until placed or destroyed */
17 extern boolean notonhead
; /* for long worms */
19 STATIC_DCL
void FDECL(kickdmg
, (struct monst
*, BOOLEAN_P
));
20 STATIC_DCL boolean
FDECL(maybe_kick_monster
, (struct monst
*,
22 STATIC_DCL
void FDECL(kick_monster
, (struct monst
*, XCHAR_P
, XCHAR_P
));
23 STATIC_DCL
int FDECL(kick_object
, (XCHAR_P
, XCHAR_P
, char *));
24 STATIC_DCL
int FDECL(really_kick_object
, (XCHAR_P
, XCHAR_P
));
25 STATIC_DCL
char *FDECL(kickstr
, (char *, const char *));
26 STATIC_DCL
void FDECL(otransit_msg
, (struct obj
*, BOOLEAN_P
, long));
27 STATIC_DCL
void FDECL(drop_to
, (coord
*, SCHAR_P
));
29 static const char kick_passes_thru
[] = "kick passes harmlessly through";
33 register struct monst
*mon
;
34 register boolean clumsy
;
36 register int mdx
, mdy
;
37 register int dmg
= (ACURRSTR
+ ACURR(A_DEX
) + ACURR(A_CON
)) / 15;
38 int kick_skill
= P_NONE
;
39 int blessed_foot_damage
= 0;
40 boolean trapkilled
= FALSE
;
42 if (uarmf
&& uarmf
->otyp
== KICKING_BOOTS
)
45 /* excessive wt affects dex, so it affects dmg */
49 /* kicking a dragon or an elephant will not harm it */
50 if (thick_skinned(mon
->data
))
53 /* attacking a shade is useless */
54 if (mon
->data
== &mons
[PM_SHADE
])
57 if ((is_undead(mon
->data
) || is_demon(mon
->data
) || is_vampshifter(mon
))
58 && uarmf
&& uarmf
->blessed
)
59 blessed_foot_damage
= 1;
61 if (mon
->data
== &mons
[PM_SHADE
] && !blessed_foot_damage
) {
62 pline_The("%s.", kick_passes_thru
);
63 /* doesn't exercise skill or abuse alignment or frighten pet,
64 and shades have no passive counterattack */
73 /* squeeze some guilt feelings... */
77 monflee(mon
, (dmg
? rnd(dmg
) : 1), FALSE
, FALSE
);
83 /* convert potential damage to actual damage */
87 kick_skill
= P_MARTIAL_ARTS
;
88 dmg
+= rn2(ACURR(A_DEX
) / 2 + 1);
90 /* a good kick exercises your dex */
91 exercise(A_DEX
, TRUE
);
93 if (blessed_foot_damage
)
97 dmg
+= u
.udaminc
; /* add ring(s) of increase damage */
100 if (mon
->mhp
> 0 && martial() && !bigmonst(mon
->data
) && !rn2(3)
101 && mon
->mcanmove
&& mon
!= u
.ustuck
&& !mon
->mtrapped
) {
102 /* see if the monster has a place to move into */
103 mdx
= mon
->mx
+ u
.dx
;
104 mdy
= mon
->my
+ u
.dy
;
105 if (goodpos(mdx
, mdy
, mon
, 0)) {
106 pline("%s reels from the blow.", Monnam(mon
));
107 if (m_in_out_region(mon
, mdx
, mdy
)) {
108 remove_monster(mon
->mx
, mon
->my
);
109 newsym(mon
->mx
, mon
->my
);
110 place_monster(mon
, mdx
, mdy
);
111 newsym(mon
->mx
, mon
->my
);
113 if (mintrap(mon
) == 2)
119 (void) passive(mon
, TRUE
, mon
->mhp
> 0, AT_KICK
, FALSE
);
120 if (mon
->mhp
<= 0 && !trapkilled
)
123 /* may bring up a dialog, so put this after all messages */
124 if (kick_skill
!= P_NONE
) /* exercise proficiency */
125 use_skill(kick_skill
, 1);
129 maybe_kick_monster(mon
, x
, y
)
134 boolean save_forcefight
= context
.forcefight
;
138 if (!mon
->mpeaceful
|| !canspotmon(mon
))
139 context
.forcefight
= TRUE
; /* attack even if invisible */
140 /* kicking might be halted by discovery of hidden monster,
141 by player declining to attack peaceful monster,
142 or by passing out due to encumbrance */
143 if (attack_checks(mon
, (struct obj
*) 0) || overexertion())
144 mon
= 0; /* don't kick after all */
145 context
.forcefight
= save_forcefight
;
147 return (boolean
) (mon
!= 0);
151 kick_monster(mon
, x
, y
)
155 boolean clumsy
= FALSE
;
158 /* anger target even if wild miss will occur */
161 if (Levitation
&& !rn2(3) && verysmall(mon
->data
)
162 && !is_flyer(mon
->data
)) {
163 pline("Floating in the air, you miss wildly!");
164 exercise(A_DEX
, FALSE
);
165 (void) passive(mon
, FALSE
, 1, AT_KICK
, FALSE
);
169 /* reveal hidden target even if kick ends up missing (note: being
170 hidden doesn't affect chance to hit so neither does this reveal) */
172 || (mon
->m_ap_type
&& mon
->m_ap_type
!= M_AP_MONSTER
)) {
175 mon
->mundetected
= 0;
176 if (!canspotmon(mon
))
181 canspotmon(mon
) ? a_monnam(mon
) : "something hidden");
184 /* Kick attacks by kicking monsters are normal attacks, not special.
185 * This is almost always worthless, since you can either take one turn
186 * and do all your kicks, or else take one turn and attack the monster
187 * normally, getting all your attacks _including_ all your kicks.
188 * If you have >1 kick attack, you get all of them.
190 if (Upolyd
&& attacktype(youmonst
.data
, AT_KICK
)) {
191 struct attack
*uattk
;
192 int sum
, kickdieroll
, armorpenalty
,
194 tmp
= find_roll_to_hit(mon
, AT_KICK
, (struct obj
*) 0, &attknum
,
197 for (i
= 0; i
< NATTK
; i
++) {
198 /* first of two kicks might have provoked counterattack
199 that has incapacitated the hero (ie, floating eye) */
203 uattk
= &youmonst
.data
->mattk
[i
];
204 /* we only care about kicking attacks here */
205 if (uattk
->aatyp
!= AT_KICK
)
208 if (mon
->data
== &mons
[PM_SHADE
] && (!uarmf
|| !uarmf
->blessed
)) {
209 /* doesn't matter whether it would have hit or missed,
210 and shades have no passive counterattack */
211 Your("%s %s.", kick_passes_thru
, mon_nam(mon
));
212 break; /* skip any additional kicks */
213 } else if (tmp
> (kickdieroll
= rnd(20))) {
214 You("kick %s.", mon_nam(mon
));
215 sum
= damageum(mon
, uattk
);
216 (void) passive(mon
, (boolean
) (sum
> 0), (sum
!= 2), AT_KICK
,
219 break; /* Defender died */
221 missum(mon
, uattk
, (tmp
+ armorpenalty
> kickdieroll
));
222 (void) passive(mon
, FALSE
, 1, AT_KICK
, FALSE
);
231 if (i
< (j
* 3) / 10) {
232 if (!rn2((i
< j
/ 10) ? 2 : (i
< j
/ 5) ? 3 : 4)) {
233 if (martial() && !rn2(2))
235 Your("clumsy kick does no damage.");
236 (void) passive(mon
, FALSE
, 1, AT_KICK
, FALSE
);
241 else if (!rn2((i
< j
/ 5) ? 2 : 3))
248 else if (uarm
&& objects
[uarm
->otyp
].oc_bulky
&& ACURR(A_DEX
) < rnd(25))
251 You("kick %s.", mon_nam(mon
));
252 if (!rn2(clumsy
? 3 : 4) && (clumsy
|| !bigmonst(mon
->data
))
253 && mon
->mcansee
&& !mon
->mtrapped
&& !thick_skinned(mon
->data
)
254 && mon
->data
->mlet
!= S_EEL
&& haseyes(mon
->data
) && mon
->mcanmove
255 && !mon
->mstun
&& !mon
->mconf
&& !mon
->msleeping
256 && mon
->data
->mmove
>= 12) {
257 if (!nohands(mon
->data
) && !rn2(martial() ? 5 : 3)) {
258 pline("%s blocks your %skick.", Monnam(mon
),
259 clumsy
? "clumsy " : "");
260 (void) passive(mon
, FALSE
, 1, AT_KICK
, FALSE
);
264 if (mon
->mx
!= x
|| mon
->my
!= y
) {
265 if (glyph_is_invisible(levl
[x
][y
].glyph
)) {
269 pline("%s %s, %s evading your %skick.", Monnam(mon
),
270 (!level
.flags
.noteleport
&& can_teleport(mon
->data
))
272 : is_floater(mon
->data
)
274 : is_flyer(mon
->data
) ? "swoops"
275 : (nolimbs(mon
->data
)
276 || slithy(mon
->data
))
279 clumsy
? "easily" : "nimbly", clumsy
? "clumsy " : "");
280 (void) passive(mon
, FALSE
, 1, AT_KICK
, FALSE
);
285 kickdmg(mon
, clumsy
);
289 * Return TRUE if caught (the gold taken care of), FALSE otherwise.
290 * The gold object is *not* attached to the fobj chain!
294 register struct monst
*mtmp
;
295 register struct obj
*gold
;
297 boolean msg_given
= FALSE
;
299 if (!likes_gold(mtmp
->data
) && !mtmp
->isshk
&& !mtmp
->ispriest
300 && !mtmp
->isgd
&& !is_mercenary(mtmp
->data
)) {
302 } else if (!mtmp
->mcanmove
) {
303 /* too light to do real damage */
304 if (canseemon(mtmp
)) {
305 pline_The("%s harmlessly %s %s.", xname(gold
),
306 otense(gold
, "hit"), mon_nam(mtmp
));
310 long umoney
, value
= gold
->quan
* objects
[gold
->otyp
].oc_cost
;
313 finish_meating(mtmp
);
314 if (!mtmp
->isgd
&& !rn2(4)) /* not always pleasing */
316 /* greedy monsters catch gold */
317 if (cansee(mtmp
->mx
, mtmp
->my
))
318 pline("%s catches the gold.", Monnam(mtmp
));
319 (void) mpickobj(mtmp
, gold
);
320 gold
= (struct obj
*) 0; /* obj has been freed */
322 long robbed
= ESHK(mtmp
)->robbed
;
328 pline_The("amount %scovers %s recent losses.",
329 !robbed
? "" : "partially ", mhis(mtmp
));
330 ESHK(mtmp
)->robbed
= robbed
;
332 make_happy_shk(mtmp
, FALSE
);
334 if (mtmp
->mpeaceful
) {
335 ESHK(mtmp
)->credit
+= value
;
336 You("have %ld %s in credit.", ESHK(mtmp
)->credit
,
337 currency(ESHK(mtmp
)->credit
));
339 verbalize("Thanks, scum!");
341 } else if (mtmp
->ispriest
) {
343 verbalize("Thank you for your contribution.");
345 verbalize("Thanks, scum!");
346 } else if (mtmp
->isgd
) {
347 umoney
= money_cnt(invent
);
348 /* Some of these are iffy, because a hostile guard
349 won't become peaceful and resume leading hero
350 out of the vault. If he did do that, player
351 could try fighting, then weasle out of being
352 killed by throwing his/her gold when losing. */
355 ? "Drop the rest and follow me."
357 ? "You still have hidden gold. Drop it now."
359 ? "I'll take care of that; please move along."
360 : "I'll take that; now get moving.");
361 } else if (is_mercenary(mtmp
->data
)) {
365 if (mtmp
->data
== &mons
[PM_SOLDIER
])
367 else if (mtmp
->data
== &mons
[PM_SERGEANT
])
369 else if (mtmp
->data
== &mons
[PM_LIEUTENANT
])
371 else if (mtmp
->data
== &mons
[PM_CAPTAIN
])
375 umoney
= money_cnt(invent
);
378 + (umoney
+ u
.ulevel
* rn2(5)) / ACURR(A_CHA
))
379 mtmp
->mpeaceful
= TRUE
;
383 verbalize("That should do. Now beat it!");
385 verbalize("That's not enough, coward!");
391 miss(xname(gold
), mtmp
);
395 /* container is kicked, dropped, thrown or otherwise impacted by player.
396 * Assumes container is on floor. Checks contents for possible damage. */
398 container_impact_dmg(obj
, x
, y
)
400 xchar x
, y
; /* coordinates where object was before the impact, not after */
403 struct obj
*otmp
, *otmp2
;
405 boolean costly
, insider
, frominv
;
407 /* only consider normal containers */
408 if (!Is_container(obj
) || !Has_contents(obj
) || Is_mbag(obj
))
411 costly
= ((shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
)))
412 && costly_spot(x
, y
));
413 insider
= (*u
.ushops
&& inside_shop(u
.ux
, u
.uy
)
414 && *in_rooms(x
, y
, SHOPBASE
) == *u
.ushops
);
415 /* if dropped or thrown, shop ownership flags are set on this obj */
416 frominv
= (obj
!= kickedobj
);
418 for (otmp
= obj
->cobj
; otmp
; otmp
= otmp2
) {
419 const char *result
= (char *) 0;
422 if (objects
[otmp
->otyp
].oc_material
== GLASS
423 && otmp
->oclass
!= GEM_CLASS
&& !obj_resists(otmp
, 33, 100)) {
425 } else if (otmp
->otyp
== EGG
&& !rn2(3)) {
429 if (otmp
->otyp
== MIRROR
)
432 /* eggs laid by you. penalty is -1 per egg, max 5,
433 * but it's always exactly 1 that breaks */
434 if (otmp
->otyp
== EGG
&& otmp
->spe
&& otmp
->corpsenm
>= LOW_PM
)
436 You_hear("a muffled %s.", result
);
438 if (frominv
&& !otmp
->unpaid
)
441 stolen_value(otmp
, x
, y
, (boolean
) shkp
->mpeaceful
, TRUE
);
443 if (otmp
->quan
> 1L) {
446 obj_extract_self(otmp
);
447 obfree(otmp
, (struct obj
*) 0);
449 /* contents of this container are no longer known */
453 if (costly
&& loss
) {
455 You("caused %ld %s worth of damage!", loss
, currency(loss
));
456 make_angry_shk(shkp
, x
, y
);
458 You("owe %s %ld %s for objects destroyed.", mon_nam(shkp
), loss
,
464 /* jacket around really_kick_object */
466 kick_object(x
, y
, kickobjnam
)
473 /* if a pile, the "top" object gets kicked */
474 kickedobj
= level
.objects
[x
][y
];
476 /* kick object; if doing is fatal, done() will clean up kickedobj */
477 Strcpy(kickobjnam
, killer_xname(kickedobj
)); /* matters iff res==0 */
478 res
= really_kick_object(x
, y
);
479 kickedobj
= (struct obj
*) 0;
484 /* guts of kick_object */
486 really_kick_object(x
, y
)
490 struct monst
*mon
, *shkp
= 0;
493 boolean costly
, isgold
, slide
= FALSE
;
495 /* kickedobj should always be set due to conditions of call */
496 if (!kickedobj
|| kickedobj
->otyp
== BOULDER
|| kickedobj
== uball
497 || kickedobj
== uchain
)
500 if ((trap
= t_at(x
, y
)) != 0
501 && (((trap
->ttyp
== PIT
|| trap
->ttyp
== SPIKED_PIT
) && !Passes_walls
)
502 || trap
->ttyp
== WEB
)) {
505 You_cant("kick %s that's in a %s!", something
,
506 Hallucination
? "tizzy" : (trap
->ttyp
== WEB
) ? "web"
511 if (Fumbling
&& !rn2(3)) {
512 Your("clumsy kick missed.");
516 if (!uarmf
&& kickedobj
->otyp
== CORPSE
517 && touch_petrifies(&mons
[kickedobj
->corpsenm
]) && !Stone_resistance
) {
518 You("kick %s with your bare %s.",
519 corpse_xname(kickedobj
, (const char *) 0, CXN_PFX_THE
),
520 makeplural(body_part(FOOT
)));
521 if (poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
)) {
522 ; /* hero has been transformed but kick continues */
524 /* normalize body shape here; foot, not body_part(FOOT) */
525 Sprintf(killer
.name
, "kicking %s barefoot",
526 killer_xname(kickedobj
));
527 instapetrify(killer
.name
);
531 /* range < 2 means the object will not move. */
532 /* maybe dexterity should also figure here. */
533 range
= (int) ((ACURRSTR
) / 2 - kickedobj
->owt
/ 40);
539 /* you're in the water too; significantly reduce range */
540 range
= range
/ 3 + 1; /* {1,2}=>1, {3,4,5}=>2, {6,7,8}=>3 */
541 } else if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)) {
542 /* you're in air, since is_pool did not match */
546 range
+= rnd(3), slide
= TRUE
;
547 if (kickedobj
->greased
)
548 range
+= rnd(3), slide
= TRUE
;
551 /* Mjollnir is magically too heavy to kick */
552 if (kickedobj
->oartifact
== ART_MJOLLNIR
)
555 /* see if the object has a place to move into */
556 if (!ZAP_POS(levl
[x
+ u
.dx
][y
+ u
.dy
].typ
)
557 || closed_door(x
+ u
.dx
, y
+ u
.dy
))
560 costly
= (!(kickedobj
->no_charge
&& !Has_contents(kickedobj
))
561 && (shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
))) != 0
562 && costly_spot(x
, y
));
563 isgold
= (kickedobj
->oclass
== COIN_CLASS
);
565 if (IS_ROCK(levl
[x
][y
].typ
) || closed_door(x
, y
)) {
566 if ((!martial() && rn2(20) > ACURR(A_DEX
))
567 || IS_ROCK(levl
[u
.ux
][u
.uy
].typ
) || closed_door(u
.ux
, u
.uy
)) {
569 pline("It doesn't come loose.");
571 pline("%s %sn't come loose.",
572 The(distant_name(kickedobj
, xname
)),
573 otense(kickedobj
, "do"));
574 return (!rn2(3) || martial());
577 pline("It comes loose.");
579 pline("%s %s loose.", The(distant_name(kickedobj
, xname
)),
580 otense(kickedobj
, "come"));
581 obj_extract_self(kickedobj
);
583 if (costly
&& (!costly_spot(u
.ux
, u
.uy
)
584 || !index(u
.urooms
, *in_rooms(x
, y
, SHOPBASE
))))
585 addtobill(kickedobj
, FALSE
, FALSE
, FALSE
);
586 if (!flooreffects(kickedobj
, u
.ux
, u
.uy
, "fall")) {
587 place_object(kickedobj
, u
.ux
, u
.uy
);
594 /* a box gets a chance of breaking open here */
595 if (Is_box(kickedobj
)) {
596 boolean otrp
= kickedobj
->otrapped
;
600 container_impact_dmg(kickedobj
, x
, y
);
601 if (kickedobj
->olocked
) {
602 if (!rn2(5) || (martial() && !rn2(2))) {
603 You("break open the lock!");
604 breakchestlock(kickedobj
, FALSE
);
606 (void) chest_trap(kickedobj
, LEG
, FALSE
);
610 if (!rn2(3) || (martial() && !rn2(2))) {
611 pline_The("lid slams open, then falls shut.");
612 kickedobj
->lknown
= 1;
614 (void) chest_trap(kickedobj
, LEG
, FALSE
);
620 /* else let it fall through to the next cases... */
623 /* fragile objects should not be kicked */
624 if (hero_breaks(kickedobj
, kickedobj
->ox
, kickedobj
->oy
, FALSE
))
627 /* too heavy to move. range is calculated as potential distance from
628 * player, so range == 2 means the object may move up to one square
629 * from its current position
632 if (!Is_box(kickedobj
))
634 return (!rn2(3) || martial());
637 if (kickedobj
->quan
> 1L) {
639 kickedobj
= splitobj(kickedobj
, 1L);
642 static NEARDATA
const char *const flyingcoinmsg
[] = {
643 "scatter the coins", "knock coins all over the place",
644 "send coins flying in all directions",
648 You("%s!", flyingcoinmsg
[rn2(SIZE(flyingcoinmsg
))]);
649 (void) scatter(x
, y
, rn2(3) + 1, VIS_EFFECTS
| MAY_HIT
,
654 if (kickedobj
->quan
> 300L) {
656 return (!rn2(3) || martial());
662 pline("Whee! %s %s across the %s.", Doname2(kickedobj
),
663 otense(kickedobj
, "slide"), surface(x
, y
));
665 if (costly
&& !isgold
)
666 addtobill(kickedobj
, FALSE
, FALSE
, TRUE
);
667 obj_extract_self(kickedobj
);
668 (void) snuff_candle(kickedobj
);
670 mon
= bhit(u
.dx
, u
.dy
, range
, KICKED_WEAPON
,
671 (int FDECL((*), (MONST_P
, OBJ_P
))) 0,
672 (int FDECL((*), (OBJ_P
, OBJ_P
))) 0, &kickedobj
);
674 return 1; /* object broken */
677 if (mon
->isshk
&& kickedobj
->where
== OBJ_MINVENT
678 && kickedobj
->ocarry
== mon
)
679 return 1; /* alert shk caught it */
680 notonhead
= (mon
->mx
!= bhitpos
.x
|| mon
->my
!= bhitpos
.y
);
681 if (isgold
? ghitm(mon
, kickedobj
) /* caught? */
682 : thitmonst(mon
, kickedobj
)) /* hit && used up? */
686 /* the object might have fallen down a hole;
687 ship_object() will have taken care of shop billing */
688 if (kickedobj
->where
== OBJ_MIGRATING
)
691 bhitroom
= *in_rooms(bhitpos
.x
, bhitpos
.y
, SHOPBASE
);
692 if (costly
&& (!costly_spot(bhitpos
.x
, bhitpos
.y
)
693 || *in_rooms(x
, y
, SHOPBASE
) != bhitroom
)) {
695 costly_gold(x
, y
, kickedobj
->quan
);
697 (void) stolen_value(kickedobj
, x
, y
, (boolean
) shkp
->mpeaceful
,
701 if (flooreffects(kickedobj
, bhitpos
.x
, bhitpos
.y
, "fall"))
703 if (kickedobj
->unpaid
)
704 subfrombill(kickedobj
, shkp
);
705 place_object(kickedobj
, bhitpos
.x
, bhitpos
.y
);
707 newsym(kickedobj
->ox
, kickedobj
->oy
);
711 /* cause of death if kicking kills kicker */
713 kickstr(buf
, kickobjnam
)
715 const char *kickobjnam
;
721 else if (maploc
== &nowhere
)
723 else if (IS_DOOR(maploc
->typ
))
725 else if (IS_TREE(maploc
->typ
))
727 else if (IS_STWALL(maploc
->typ
))
729 else if (IS_ROCK(maploc
->typ
))
731 else if (IS_THRONE(maploc
->typ
))
733 else if (IS_FOUNTAIN(maploc
->typ
))
735 else if (IS_GRAVE(maploc
->typ
))
736 what
= "a headstone";
737 else if (IS_SINK(maploc
->typ
))
739 else if (IS_ALTAR(maploc
->typ
))
741 else if (IS_DRAWBRIDGE(maploc
->typ
))
742 what
= "a drawbridge";
743 else if (maploc
->typ
== STAIRS
)
745 else if (maploc
->typ
== LADDER
)
747 else if (maploc
->typ
== IRONBARS
)
748 what
= "an iron bar";
750 what
= "something weird";
751 return strcat(strcpy(buf
, "kicking "), what
);
759 int dmg
= 0, glyph
, oldglyph
= -1;
760 register struct monst
*mtmp
;
761 boolean no_kick
= FALSE
;
762 char buf
[BUFSZ
], kickobjnam
[BUFSZ
];
764 kickobjnam
[0] = '\0';
765 if (nolimbs(youmonst
.data
) || slithy(youmonst
.data
)) {
766 You("have no legs to kick with.");
768 } else if (verysmall(youmonst
.data
)) {
769 You("are too small to do any kicking.");
771 } else if (u
.usteed
) {
772 if (yn_function("Kick your steed?", ynchars
, 'y') == 'y') {
773 You("kick %s.", mon_nam(u
.usteed
));
779 } else if (Wounded_legs
) {
780 /* note: jump() has similar code */
781 long wl
= (EWounded_legs
& BOTH_SIDES
);
782 const char *bp
= body_part(LEG
);
784 if (wl
== BOTH_SIDES
)
786 Your("%s%s %s in no shape for kicking.",
787 (wl
== LEFT_SIDE
) ? "left " : (wl
== RIGHT_SIDE
) ? "right " : "",
788 bp
, (wl
== BOTH_SIDES
) ? "are" : "is");
790 } else if (near_capacity() > SLT_ENCUMBER
) {
791 Your("load is too heavy to balance yourself for a kick.");
793 } else if (youmonst
.data
->mlet
== S_LIZARD
) {
794 Your("legs cannot kick effectively.");
796 } else if (u
.uinwater
&& !rn2(2)) {
797 Your("slow motion kick doesn't hit anything.");
799 } else if (u
.utrap
) {
801 switch (u
.utraptype
) {
804 pline("There's not enough room to kick down here.");
810 You_cant("move your %s!", body_part(LEG
));
818 /* ignore direction typed before player notices kick failed */
819 display_nhwindow(WIN_MESSAGE
, TRUE
); /* --More-- */
823 if (!getdir((char *) 0))
831 /* KMH -- Kicking boots always succeed */
832 if (uarmf
&& uarmf
->otyp
== KICKING_BOOTS
)
835 avrg_attrib
= (ACURRSTR
+ ACURR(A_DEX
) + ACURR(A_CON
)) / 3;
840 You_cant("move your %s!", body_part(LEG
));
843 if (is_animal(u
.ustuck
->data
)) {
844 pline("%s burps loudly.", Monnam(u
.ustuck
));
848 Your("feeble kick has no effect.");
852 } else if (u
.utrap
&& u
.utraptype
== TT_PIT
) {
853 /* must be Passes_walls */
854 You("kick at the side of the pit.");
862 /* doors can be opened while levitating, so they must be
863 * reachable for bracing purposes
864 * Possible extension: allow bracing against stuff on the side?
866 if (isok(xx
, yy
) && !IS_ROCK(levl
[xx
][yy
].typ
)
867 && !IS_DOOR(levl
[xx
][yy
].typ
)
868 && (!Is_airlevel(&u
.uz
) || !OBJ_AT(xx
, yy
))) {
869 You("have nothing to brace yourself against.");
874 mtmp
= isok(x
, y
) ? m_at(x
, y
) : 0;
875 /* might not kick monster if it is hidden and becomes revealed,
876 if it is peaceful and player declines to attack, or if the
877 hero passes out due to encumbrance with low hp; context.move
878 will be 1 unless player declines to kick peaceful monster */
880 oldglyph
= glyph_at(x
, y
);
881 if (!maybe_kick_monster(mtmp
, x
, y
))
892 maploc
= &levl
[x
][y
];
895 * The next five tests should stay in their present order:
896 * monsters, pools, objects, non-doors, doors.
898 * [FIXME: Monsters who are hidden underneath objects or
899 * in pools should lead to hero kicking the concealment
900 * rather than the monster, probably exposing the hidden
901 * monster in the process. And monsters who are hidden on
902 * ceiling shouldn't be kickable (unless hero is flying?);
903 * kicking toward them should just target whatever is on
904 * the floor at that spot.]
908 /* save mtmp->data (for recoil) in case mtmp gets killed */
909 struct permonst
*mdat
= mtmp
->data
;
911 kick_monster(mtmp
, x
, y
);
912 glyph
= glyph_at(x
, y
);
913 /* see comment in attack_checks() */
914 if (mtmp
->mhp
<= 0) { /* DEADMONSTER() */
915 /* if we mapped an invisible monster and immediately
916 killed it, we don't want to forget what we thought
917 was there before the kick */
918 if (glyph
!= oldglyph
&& glyph_is_invisible(glyph
))
919 show_glyph(x
, y
, oldglyph
);
920 } else if (!canspotmon(mtmp
)
921 /* check <x,y>; monster that evades kick by jumping
922 to an unseen square doesn't leave an I behind */
923 && mtmp
->mx
== x
&& mtmp
->my
== y
924 && !glyph_is_invisible(glyph
)
925 && !(u
.uswallow
&& mtmp
== u
.ustuck
)) {
928 /* recoil if floating */
929 if ((Is_airlevel(&u
.uz
) || Levitation
) && context
.move
) {
933 ((int) youmonst
.data
->cwt
+ (weight_cap() + inv_weight()));
935 range
= 1; /* divide by zero avoidance */
936 range
= (3 * (int) mdat
->cwt
) / range
;
940 hurtle(-u
.dx
, -u
.dy
, range
, TRUE
);
944 if (glyph_is_invisible(levl
[x
][y
].glyph
)) {
948 if (is_pool(x
, y
) ^ !!u
.uinwater
) {
949 /* objects normally can't be removed from water by kicking */
950 You("splash some water around.");
954 if (OBJ_AT(x
, y
) && (!Levitation
|| Is_airlevel(&u
.uz
)
955 || Is_waterlevel(&u
.uz
) || sobj_at(BOULDER
, x
, y
))) {
956 if (kick_object(x
, y
, kickobjnam
)) {
957 if (Is_airlevel(&u
.uz
))
958 hurtle(-u
.dx
, -u
.dy
, 1, TRUE
); /* assume it's light */
964 if (!IS_DOOR(maploc
->typ
)) {
965 if (maploc
->typ
== SDOOR
) {
966 if (!Levitation
&& rn2(30) < avrg_attrib
) {
967 cvt_sdoor_to_door(maploc
); /* ->typ = DOOR */
968 pline("Crash! %s a secret door!",
969 /* don't "kick open" when it's locked
970 unless it also happens to be trapped */
971 (maploc
->doormask
& (D_LOCKED
| D_TRAPPED
)) == D_LOCKED
972 ? "Your kick uncovers"
974 exercise(A_DEX
, TRUE
);
975 if (maploc
->doormask
& D_TRAPPED
) {
976 maploc
->doormask
= D_NODOOR
;
977 b_trapped("door", FOOT
);
978 } else if (maploc
->doormask
!= D_NODOOR
979 && !(maploc
->doormask
& D_LOCKED
))
980 maploc
->doormask
= D_ISOPEN
;
981 feel_newsym(x
, y
); /* we know it's gone */
982 if (maploc
->doormask
== D_ISOPEN
983 || maploc
->doormask
== D_NODOOR
)
984 unblock_point(x
, y
); /* vision */
989 if (maploc
->typ
== SCORR
) {
990 if (!Levitation
&& rn2(30) < avrg_attrib
) {
991 pline("Crash! You kick open a secret passage!");
992 exercise(A_DEX
, TRUE
);
994 feel_newsym(x
, y
); /* we know it's gone */
995 unblock_point(x
, y
); /* vision */
1000 if (IS_THRONE(maploc
->typ
)) {
1004 if ((Luck
< 0 || maploc
->doormask
) && !rn2(3)) {
1006 maploc
->doormask
= 0; /* don't leave loose ends.. */
1007 (void) mkgold((long) rnd(200), x
, y
);
1009 pline("CRASH! You destroy it.");
1011 pline("CRASH! You destroy the throne.");
1014 exercise(A_DEX
, TRUE
);
1016 } else if (Luck
> 0 && !rn2(3) && !maploc
->looted
) {
1017 (void) mkgold((long) rn1(201, 300), x
, y
);
1023 rnd_class(DILITHIUM_CRYSTAL
, LUCKSTONE
- 1), x
, y
,
1026 You("kick %s loose!", something
);
1028 You("kick loose some ornamental coins and gems!");
1031 /* prevent endless milking */
1032 maploc
->looted
= T_LOOTED
;
1034 } else if (!rn2(4)) {
1035 if (dunlev(&u
.uz
) < dunlevs_in_dungeon(&u
.uz
)) {
1036 fall_through(FALSE
);
1043 if (IS_ALTAR(maploc
->typ
)) {
1046 You("kick %s.", (Blind
? something
: "the altar"));
1050 exercise(A_DEX
, TRUE
);
1053 if (IS_FOUNTAIN(maploc
->typ
)) {
1056 You("kick %s.", (Blind
? something
: "the fountain"));
1059 /* make metal boots rust */
1060 if (uarmf
&& rn2(3))
1061 if (water_damage(uarmf
, "metal boots", TRUE
) == ER_NOTHING
) {
1062 Your("boots get wet.");
1063 /* could cause short-lived fumbling here */
1065 exercise(A_DEX
, TRUE
);
1068 if (IS_GRAVE(maploc
->typ
)) {
1073 exercise(A_WIS
, FALSE
);
1074 if (Role_if(PM_ARCHEOLOGIST
) || Role_if(PM_SAMURAI
)
1075 || ((u
.ualign
.type
== A_LAWFUL
) && (u
.ualign
.record
> -10))) {
1076 adjalign(-sgn(u
.ualign
.type
));
1079 maploc
->doormask
= 0;
1080 (void) mksobj_at(ROCK
, x
, y
, TRUE
, FALSE
);
1083 pline("Crack! %s broke!", Something
);
1085 pline_The("headstone topples over and breaks!");
1090 if (maploc
->typ
== IRONBARS
)
1092 if (IS_TREE(maploc
->typ
)) {
1093 struct obj
*treefruit
;
1094 /* nothing, fruit or trouble? 75:23.5:1.5% */
1096 if (!rn2(6) && !(mvitals
[PM_KILLER_BEE
].mvflags
& G_GONE
))
1097 You_hear("a low buzzing."); /* a warning */
1100 if (rn2(15) && !(maploc
->looted
& TREE_LOOTED
)
1101 && (treefruit
= rnd_treefruit_at(x
, y
))) {
1102 long nfruit
= 8L - rnl(7), nfall
;
1103 short frtype
= treefruit
->otyp
;
1104 treefruit
->quan
= nfruit
;
1105 if (is_plural(treefruit
))
1106 pline("Some %s fall from the tree!", xname(treefruit
));
1108 pline("%s falls from the tree!", An(xname(treefruit
)));
1109 nfall
= scatter(x
, y
, 2, MAY_HIT
, treefruit
);
1110 if (nfall
!= nfruit
) {
1111 /* scatter left some in the tree, but treefruit
1112 * may not refer to the correct object */
1113 treefruit
= mksobj(frtype
, TRUE
, FALSE
);
1114 treefruit
->quan
= nfruit
- nfall
;
1115 pline("%ld %s got caught in the branches.",
1116 nfruit
- nfall
, xname(treefruit
));
1117 dealloc_obj(treefruit
);
1119 exercise(A_DEX
, TRUE
);
1120 exercise(A_WIS
, TRUE
); /* discovered a new food source! */
1122 maploc
->looted
|= TREE_LOOTED
;
1124 } else if (!(maploc
->looted
& TREE_SWARM
)) {
1125 int cnt
= rnl(4) + 2;
1131 if (enexto(&mm
, mm
.x
, mm
.y
, &mons
[PM_KILLER_BEE
])
1132 && makemon(&mons
[PM_KILLER_BEE
], mm
.x
, mm
.y
,
1137 pline("You've attracted the tree's former occupants!");
1139 You("smell stale honey.");
1140 maploc
->looted
|= TREE_SWARM
;
1145 if (IS_SINK(maploc
->typ
)) {
1146 int gend
= poly_gender();
1147 short washerndx
= (gend
== 1 || (gend
== 2 && rn2(2)))
1155 pline("Klunk! The pipes vibrate noisily.");
1158 exercise(A_DEX
, TRUE
);
1160 } else if (!(maploc
->looted
& S_LPUDDING
) && !rn2(3)
1161 && !(mvitals
[PM_BLACK_PUDDING
].mvflags
& G_GONE
)) {
1163 You_hear("a gushing sound.");
1165 pline("A %s ooze gushes up from the drain!",
1167 (void) makemon(&mons
[PM_BLACK_PUDDING
], x
, y
, NO_MM_FLAGS
);
1168 exercise(A_DEX
, TRUE
);
1170 maploc
->looted
|= S_LPUDDING
;
1172 } else if (!(maploc
->looted
& S_LDWASHER
) && !rn2(3)
1173 && !(mvitals
[washerndx
].mvflags
& G_GONE
)) {
1174 /* can't resist... */
1175 pline("%s returns!", (Blind
? Something
: "The dish washer"));
1176 if (makemon(&mons
[washerndx
], x
, y
, NO_MM_FLAGS
))
1178 maploc
->looted
|= S_LDWASHER
;
1179 exercise(A_DEX
, TRUE
);
1181 } else if (!rn2(3)) {
1183 (Blind
? "You hear a sloshing sound"
1184 : "Muddy waste pops up from the drain"));
1185 if (!(maploc
->looted
& S_LRING
)) { /* once per sink */
1187 You_see("a ring shining in its midst.");
1188 (void) mkobj_at(RING_CLASS
, x
, y
, TRUE
);
1190 exercise(A_DEX
, TRUE
);
1191 exercise(A_WIS
, TRUE
); /* a discovery! */
1192 maploc
->looted
|= S_LRING
;
1198 if (maploc
->typ
== STAIRS
|| maploc
->typ
== LADDER
1199 || IS_STWALL(maploc
->typ
)) {
1200 if (!IS_STWALL(maploc
->typ
) && maploc
->ladder
== LA_DOWN
)
1203 pline("Ouch! That hurts!");
1204 exercise(A_DEX
, FALSE
);
1205 exercise(A_STR
, FALSE
);
1208 feel_location(x
, y
); /* we know we hit it */
1209 if (is_drawbridge_wall(x
, y
) >= 0) {
1210 pline_The("drawbridge is unaffected.");
1211 /* update maploc to refer to the drawbridge */
1212 (void) find_drawbridge(&x
, &y
);
1213 maploc
= &levl
[x
][y
];
1217 set_wounded_legs(RIGHT_SIDE
, 5 + rnd(5));
1218 dmg
= rnd(ACURR(A_CON
) > 15 ? 3 : 5);
1219 losehp(Maybe_Half_Phys(dmg
), kickstr(buf
, kickobjnam
), KILLED_BY
);
1220 if (Is_airlevel(&u
.uz
) || Levitation
)
1221 hurtle(-u
.dx
, -u
.dy
, rn1(2, 4), TRUE
); /* assume it's heavy */
1227 if (maploc
->doormask
== D_ISOPEN
|| maploc
->doormask
== D_BROKEN
1228 || maploc
->doormask
== D_NODOOR
) {
1230 exercise(A_DEX
, FALSE
);
1231 if (martial() || ACURR(A_DEX
) >= 16 || rn2(3)) {
1232 You("kick at empty space.");
1234 feel_location(x
, y
);
1236 pline("Dumb move! You strain a muscle.");
1237 exercise(A_STR
, FALSE
);
1238 set_wounded_legs(RIGHT_SIDE
, 5 + rnd(5));
1240 if ((Is_airlevel(&u
.uz
) || Levitation
) && rn2(2))
1241 hurtle(-u
.dx
, -u
.dy
, 1, TRUE
);
1242 return 1; /* uses a turn */
1245 /* not enough leverage to kick open doors while levitating */
1249 exercise(A_DEX
, TRUE
);
1250 /* door is known to be CLOSED or LOCKED */
1251 if (rnl(35) < avrg_attrib
+ (!martial() ? 0 : ACURR(A_DEX
))) {
1252 boolean shopdoor
= *in_rooms(x
, y
, SHOPBASE
) ? TRUE
: FALSE
;
1253 /* break the door */
1254 if (maploc
->doormask
& D_TRAPPED
) {
1256 You("kick the door.");
1257 exercise(A_STR
, FALSE
);
1258 maploc
->doormask
= D_NODOOR
;
1259 b_trapped("door", FOOT
);
1260 } else if (ACURR(A_STR
) > 18 && !rn2(5) && !shopdoor
) {
1261 pline("As you kick the door, it shatters to pieces!");
1262 exercise(A_STR
, TRUE
);
1263 maploc
->doormask
= D_NODOOR
;
1265 pline("As you kick the door, it crashes open!");
1266 exercise(A_STR
, TRUE
);
1267 maploc
->doormask
= D_BROKEN
;
1269 feel_newsym(x
, y
); /* we know we broke it */
1270 unblock_point(x
, y
); /* vision */
1272 add_damage(x
, y
, 400L);
1273 pay_for_damage("break", FALSE
);
1276 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
1277 if (DEADMONSTER(mtmp
))
1279 if (is_watch(mtmp
->data
) && couldsee(mtmp
->mx
, mtmp
->my
)
1280 && mtmp
->mpeaceful
) {
1281 mon_yells(mtmp
, "Halt, thief! You're under arrest!");
1282 (void) angry_guards(FALSE
);
1288 feel_location(x
, y
); /* we know we hit it */
1289 exercise(A_STR
, TRUE
);
1292 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
1293 if (DEADMONSTER(mtmp
))
1295 if (is_watch(mtmp
->data
) && mtmp
->mpeaceful
1296 && couldsee(mtmp
->mx
, mtmp
->my
)) {
1297 if (levl
[x
][y
].looted
& D_WARNED
) {
1299 "Halt, vandal! You're under arrest!");
1300 (void) angry_guards(FALSE
);
1302 mon_yells(mtmp
, "Hey, stop damaging that door!");
1303 levl
[x
][y
].looted
|= D_WARNED
;
1317 /* cover all the MIGR_xxx choices generated by down_gate() */
1319 case MIGR_RANDOM
: /* trap door or hole */
1320 if (Is_stronghold(&u
.uz
)) {
1321 cc
->x
= valley_level
.dnum
;
1322 cc
->y
= valley_level
.dlevel
;
1324 } else if (In_endgame(&u
.uz
) || Is_botlevel(&u
.uz
)) {
1327 } /* else fall to the next cases */
1328 case MIGR_STAIRS_UP
:
1329 case MIGR_LADDER_UP
:
1331 cc
->y
= u
.uz
.dlevel
+ 1;
1334 cc
->x
= sstairs
.tolev
.dnum
;
1335 cc
->y
= sstairs
.tolev
.dlevel
;
1339 /* y==0 means "nowhere", in which case x doesn't matter */
1345 /* player or missile impacts location, causing objects to fall down */
1347 impact_drop(missile
, x
, y
, dlev
)
1348 struct obj
*missile
; /* caused impact, won't drop itself */
1349 xchar x
, y
; /* location affected */
1350 xchar dlev
; /* if !0 send to dlev near player */
1353 register struct obj
*obj
, *obj2
;
1354 register struct monst
*shkp
;
1355 long oct
, dct
, price
, debit
, robbed
;
1356 boolean angry
, costly
, isrock
;
1362 toloc
= down_gate(x
, y
);
1363 drop_to(&cc
, toloc
);
1368 /* send objects next to player falling through trap door.
1369 * checked in obj_delivery().
1371 toloc
= MIGR_WITH_HERO
;
1375 costly
= costly_spot(x
, y
);
1376 price
= debit
= robbed
= 0L;
1378 shkp
= (struct monst
*) 0;
1379 /* if 'costly', we must keep a record of ESHK(shkp) before
1380 * it undergoes changes through the calls to stolen_value.
1381 * the angry bit must be reset, if needed, in this fn, since
1382 * stolen_value is called under the 'silent' flag to avoid
1383 * unsavory pline repetitions.
1386 if ((shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
))) != 0) {
1387 debit
= ESHK(shkp
)->debit
;
1388 robbed
= ESHK(shkp
)->robbed
;
1389 angry
= !shkp
->mpeaceful
;
1393 isrock
= (missile
&& missile
->otyp
== ROCK
);
1395 for (obj
= level
.objects
[x
][y
]; obj
; obj
= obj2
) {
1396 obj2
= obj
->nexthere
;
1399 /* number of objects in the pile */
1401 if (obj
== uball
|| obj
== uchain
)
1403 /* boulders can fall too, but rarely & never due to rocks */
1404 if ((isrock
&& obj
->otyp
== BOULDER
)
1405 || rn2(obj
->otyp
== BOULDER
? 30 : 3))
1407 obj_extract_self(obj
);
1410 price
+= stolen_value(
1411 obj
, x
, y
, (costly_spot(u
.ux
, u
.uy
)
1412 && index(u
.urooms
, *in_rooms(x
, y
, SHOPBASE
))),
1414 /* set obj->no_charge to 0 */
1415 if (Has_contents(obj
))
1416 picked_container(obj
); /* does the right thing */
1417 if (obj
->oclass
!= COIN_CLASS
)
1421 add_to_migration(obj
);
1424 obj
->owornmask
= (long) toloc
;
1426 /* number of fallen objects */
1430 if (dct
&& cansee(x
, y
)) { /* at least one object fell */
1431 const char *what
= (dct
== 1L ? "object falls" : "objects fall");
1434 pline("From the impact, %sother %s.",
1435 dct
== oct
? "the " : dct
== 1L ? "an" : "", what
);
1436 else if (oct
== dct
)
1437 pline("%s adjacent %s %s.", dct
== 1L ? "The" : "All the", what
,
1440 pline("%s adjacent %s %s.",
1441 dct
== 1L ? "One of the" : "Some of the",
1442 dct
== 1L ? "objects falls" : what
, gate_str
);
1445 if (costly
&& shkp
&& price
) {
1446 if (ESHK(shkp
)->robbed
> robbed
) {
1447 You("removed %ld %s worth of goods!", price
, currency(price
));
1448 if (cansee(shkp
->mx
, shkp
->my
)) {
1449 if (ESHK(shkp
)->customer
[0] == 0)
1450 (void) strncpy(ESHK(shkp
)->customer
, plname
, PL_NSIZ
);
1452 pline("%s is infuriated!", Monnam(shkp
));
1454 pline("\"%s, you are a thief!\"", plname
);
1456 You_hear("a scream, \"Thief!\"");
1458 (void) angry_guards(FALSE
);
1461 if (ESHK(shkp
)->debit
> debit
) {
1462 long amt
= (ESHK(shkp
)->debit
- debit
);
1463 You("owe %s %ld %s for goods lost.", Monnam(shkp
), amt
,
1469 /* NOTE: ship_object assumes otmp was FREED from fobj or invent.
1470 * <x,y> is the point of drop. otmp is _not_ an <x,y> resident:
1471 * otmp is either a kicked, dropped, or thrown object.
1474 ship_object(otmp
, x
, y
, shop_floor_obj
)
1477 boolean shop_floor_obj
;
1484 boolean nodrop
, unpaid
, container
, impact
= FALSE
;
1489 if ((toloc
= down_gate(x
, y
)) == MIGR_NOWHERE
)
1491 drop_to(&cc
, toloc
);
1495 /* objects other than attached iron ball always fall down ladder,
1496 but have a chance of staying otherwise */
1497 nodrop
= (otmp
== uball
) || (otmp
== uchain
)
1498 || (toloc
!= MIGR_LADDER_UP
&& rn2(3));
1500 container
= Has_contents(otmp
);
1501 unpaid
= is_unpaid(otmp
);
1504 for (obj
= level
.objects
[x
][y
]; obj
; obj
= obj
->nexthere
)
1510 /* boulders never fall through trap doors, but they might knock
1511 other things down before plugging the hole */
1512 if (otmp
->otyp
== BOULDER
&& ((t
= t_at(x
, y
)) != 0)
1513 && (t
->ttyp
== TRAPDOOR
|| t
->ttyp
== HOLE
)) {
1515 impact_drop(otmp
, x
, y
, 0);
1516 return FALSE
; /* let caller finish the drop */
1520 otransit_msg(otmp
, nodrop
, n
);
1524 impact_drop(otmp
, x
, y
, 0);
1528 if (unpaid
|| shop_floor_obj
) {
1530 (void) stolen_value(otmp
, u
.ux
, u
.uy
, TRUE
, FALSE
);
1534 (void) stolen_value(
1536 (costly_spot(u
.ux
, u
.uy
)
1537 && index(u
.urooms
, *in_rooms(ox
, oy
, SHOPBASE
))),
1540 /* set otmp->no_charge to 0 */
1542 picked_container(otmp
); /* happens to do the right thing */
1543 if (otmp
->oclass
!= COIN_CLASS
)
1544 otmp
->no_charge
= 0;
1547 if (otmp
->owornmask
)
1548 remove_worn_item(otmp
, TRUE
);
1550 /* some things break rather than ship */
1551 if (breaktest(otmp
)) {
1554 if (objects
[otmp
->otyp
].oc_material
== GLASS
1555 || otmp
->otyp
== EXPENSIVE_CAMERA
) {
1556 if (otmp
->otyp
== MIRROR
)
1560 /* penalty for breaking eggs laid by you */
1561 if (otmp
->otyp
== EGG
&& otmp
->spe
&& otmp
->corpsenm
>= LOW_PM
)
1562 change_luck((schar
) -min(otmp
->quan
, 5L));
1565 You_hear("a muffled %s.", result
);
1566 obj_extract_self(otmp
);
1567 obfree(otmp
, (struct obj
*) 0);
1571 add_to_migration(otmp
);
1574 otmp
->owornmask
= (long) toloc
;
1575 /* boulder from rolling boulder trap, no longer part of the trap */
1576 if (otmp
->otyp
== BOULDER
)
1580 /* the objs impacted may be in a shop other than
1581 * the one in which the hero is located. another
1582 * check for a shk is made in impact_drop. it is, e.g.,
1583 * possible to kick/throw an object belonging to one
1584 * shop into another shop through a gap in the wall,
1585 * and cause objects belonging to the other shop to
1586 * fall down a trap door--thereby getting two shopkeepers
1587 * angry at the hero in one shot.
1589 impact_drop(otmp
, x
, y
, 0);
1596 obj_delivery(near_hero
)
1599 register struct obj
*otmp
, *otmp2
;
1600 register int nx
, ny
;
1602 boolean nobreak
, noscatter
;
1604 for (otmp
= migrating_objs
; otmp
; otmp
= otmp2
) {
1606 if (otmp
->ox
!= u
.uz
.dnum
|| otmp
->oy
!= u
.uz
.dlevel
)
1609 where
= (int) (otmp
->owornmask
& 0x7fffL
); /* destination code */
1610 nobreak
= (where
& MIGR_NOBREAK
) != 0;
1611 noscatter
= (where
& MIGR_WITH_HERO
) != 0;
1612 where
&= ~(MIGR_NOBREAK
| MIGR_NOSCATTER
);
1614 if (!near_hero
^ (where
== MIGR_WITH_HERO
))
1617 obj_extract_self(otmp
);
1618 otmp
->owornmask
= 0L;
1621 case MIGR_STAIRS_UP
:
1622 nx
= xupstair
, ny
= yupstair
;
1624 case MIGR_LADDER_UP
:
1625 nx
= xupladder
, ny
= yupladder
;
1628 nx
= sstairs
.sx
, ny
= sstairs
.sy
;
1630 case MIGR_WITH_HERO
:
1631 nx
= u
.ux
, ny
= u
.uy
;
1639 place_object(otmp
, nx
, ny
);
1640 if (!nobreak
&& !IS_SOFT(levl
[nx
][ny
].typ
)) {
1641 if (where
== MIGR_WITH_HERO
) {
1642 if (breaks(otmp
, nx
, ny
))
1644 } else if (breaktest(otmp
)) {
1645 /* assume it broke before player arrived, no messages */
1652 (void) scatter(nx
, ny
, rnd(2), 0, otmp
);
1653 } else { /* random location */
1654 /* set dummy coordinates because there's no
1655 current position for rloco() to update */
1656 otmp
->ox
= otmp
->oy
= 0;
1657 if (rloco(otmp
) && !nobreak
&& breaktest(otmp
)) {
1658 /* assume it broke before player arrived, no messages */
1666 otransit_msg(otmp
, nodrop
, num
)
1667 register struct obj
*otmp
;
1668 register boolean nodrop
;
1673 Sprintf(obuf
, "%s%s",
1674 (otmp
->otyp
== CORPSE
&& type_is_pname(&mons
[otmp
->corpsenm
]))
1679 if (num
) { /* means: other objects are impacted */
1680 Sprintf(eos(obuf
), " %s %s object%s", otense(otmp
, "hit"),
1681 num
== 1L ? "another" : "other", num
> 1L ? "s" : "");
1683 Sprintf(eos(obuf
), ".");
1685 Sprintf(eos(obuf
), " and %s %s.", otense(otmp
, "fall"), gate_str
);
1688 pline("%s %s %s.", obuf
, otense(otmp
, "fall"), gate_str
);
1691 /* migration destination for objects which fall down to next level */
1699 /* this matches the player restriction in goto_level() */
1700 if (on_level(&u
.uz
, &qstart_level
) && !ok_to_quest())
1701 return MIGR_NOWHERE
;
1703 if ((xdnstair
== x
&& ydnstair
== y
)
1704 || (sstairs
.sx
== x
&& sstairs
.sy
== y
&& !sstairs
.up
)) {
1705 gate_str
= "down the stairs";
1706 return (xdnstair
== x
&& ydnstair
== y
) ? MIGR_STAIRS_UP
1709 if (xdnladder
== x
&& ydnladder
== y
) {
1710 gate_str
= "down the ladder";
1711 return MIGR_LADDER_UP
;
1714 if (((ttmp
= t_at(x
, y
)) != 0 && ttmp
->tseen
)
1715 && (ttmp
->ttyp
== TRAPDOOR
|| ttmp
->ttyp
== HOLE
)) {
1716 gate_str
= (ttmp
->ttyp
== TRAPDOOR
) ? "through the trap door"
1717 : "through the hole";
1720 return MIGR_NOWHERE
;