OSDN Git Service

ca4e2a6bc2225e055e0e1cba34aa0bd2e2769f1e
[jnethack/source.git] / src / dokick.c
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. */
4
5 #include "hack.h"
6
7 #define is_bigfoot(x) ((x) == &mons[PM_SASQUATCH])
8 #define martial()                                 \
9     (martial_bonus() || is_bigfoot(youmonst.data) \
10      || (uarmf && uarmf->otyp == KICKING_BOOTS))
11
12 static NEARDATA struct rm *maploc, nowhere;
13 static NEARDATA const char *gate_str;
14
15 /* kickedobj (decl.c) tracks a kicked object until placed or destroyed */
16
17 extern boolean notonhead; /* for long worms */
18
19 STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P));
20 STATIC_DCL boolean FDECL(maybe_kick_monster, (struct monst *,
21                                               XCHAR_P, XCHAR_P));
22 STATIC_DCL void FDECL(kick_monster, (struct monst *, XCHAR_P, XCHAR_P));
23 STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P));
24 STATIC_DCL int FDECL(really_kick_object, (XCHAR_P, XCHAR_P));
25 STATIC_DCL char *FDECL(kickstr, (char *));
26 STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long));
27 STATIC_DCL void FDECL(drop_to, (coord *, SCHAR_P));
28
29 static const char kick_passes_thru[] = "kick passes harmlessly through";
30
31 STATIC_OVL void
32 kickdmg(mon, clumsy)
33 register struct monst *mon;
34 register boolean clumsy;
35 {
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;
41
42     if (uarmf && uarmf->otyp == KICKING_BOOTS)
43         dmg += 5;
44
45     /* excessive wt affects dex, so it affects dmg */
46     if (clumsy)
47         dmg /= 2;
48
49     /* kicking a dragon or an elephant will not harm it */
50     if (thick_skinned(mon->data))
51         dmg = 0;
52
53     /* attacking a shade is useless */
54     if (mon->data == &mons[PM_SHADE])
55         dmg = 0;
56
57     if ((is_undead(mon->data) || is_demon(mon->data) || is_vampshifter(mon))
58         && uarmf && uarmf->blessed)
59         blessed_foot_damage = 1;
60
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 */
65         return;
66     }
67
68     if (mon->m_ap_type)
69         seemimic(mon);
70
71     check_caitiff(mon);
72
73     /* squeeze some guilt feelings... */
74     if (mon->mtame) {
75         abuse_dog(mon);
76         if (mon->mtame)
77             monflee(mon, (dmg ? rnd(dmg) : 1), FALSE, FALSE);
78         else
79             mon->mflee = 0;
80     }
81
82     if (dmg > 0) {
83         /* convert potential damage to actual damage */
84         dmg = rnd(dmg);
85         if (martial()) {
86             if (dmg > 1)
87                 kick_skill = P_MARTIAL_ARTS;
88             dmg += rn2(ACURR(A_DEX) / 2 + 1);
89         }
90         /* a good kick exercises your dex */
91         exercise(A_DEX, TRUE);
92     }
93     if (blessed_foot_damage)
94         dmg += rnd(4);
95     if (uarmf)
96         dmg += uarmf->spe;
97     dmg += u.udaminc; /* add ring(s) of increase damage */
98     if (dmg > 0)
99         mon->mhp -= dmg;
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);
112                 set_apparxy(mon);
113                 if (mintrap(mon) == 2)
114                     trapkilled = TRUE;
115             }
116         }
117     }
118
119     (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK, FALSE);
120     if (mon->mhp <= 0 && !trapkilled)
121         killed(mon);
122
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);
126 }
127
128 STATIC_OVL boolean
129 maybe_kick_monster(mon, x, y)
130 struct monst *mon;
131 xchar x, y;
132 {
133     if (mon) {
134         boolean save_forcefight = context.forcefight;
135
136         bhitpos.x = x;
137         bhitpos.y = y;
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;
146     }
147     return (boolean) (mon != 0);
148 }
149
150 STATIC_OVL void
151 kick_monster(mon, x, y)
152 struct monst *mon;
153 xchar x, y;
154 {
155     boolean clumsy = FALSE;
156     int i, j;
157
158     /* anger target even if wild miss will occur */
159     setmangry(mon);
160
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);
166         return;
167     }
168
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) */
171     if (mon->mundetected
172         || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER)) {
173         if (mon->m_ap_type)
174             seemimic(mon);
175         mon->mundetected = 0;
176         if (!canspotmon(mon))
177             map_invisible(x, y);
178         else
179             newsym(x, y);
180         There("is %s here.",
181               canspotmon(mon) ? a_monnam(mon) : "something hidden");
182     }
183
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.
189      */
190     if (Upolyd && attacktype(youmonst.data, AT_KICK)) {
191         struct attack *uattk;
192         int sum, kickdieroll, armorpenalty,
193             attknum = 0,
194             tmp = find_roll_to_hit(mon, AT_KICK, (struct obj *) 0, &attknum,
195                                    &armorpenalty);
196
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) */
200             if (multi < 0)
201                 break;
202
203             uattk = &youmonst.data->mattk[i];
204             /* we only care about kicking attacks here */
205             if (uattk->aatyp != AT_KICK)
206                 continue;
207
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,
217                                FALSE);
218                 if (sum == 2)
219                     break; /* Defender died */
220             } else {
221                 missum(mon, uattk, (tmp + armorpenalty > kickdieroll));
222                 (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
223             }
224         }
225         return;
226     }
227
228     i = -inv_weight();
229     j = weight_cap();
230
231     if (i < (j * 3) / 10) {
232         if (!rn2((i < j / 10) ? 2 : (i < j / 5) ? 3 : 4)) {
233             if (martial() && !rn2(2))
234                 goto doit;
235             Your("clumsy kick does no damage.");
236             (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
237             return;
238         }
239         if (i < j / 10)
240             clumsy = TRUE;
241         else if (!rn2((i < j / 5) ? 2 : 3))
242             clumsy = TRUE;
243     }
244
245     if (Fumbling)
246         clumsy = TRUE;
247
248     else if (uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
249         clumsy = TRUE;
250 doit:
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);
261             return;
262         } else {
263             maybe_mnexto(mon);
264             if (mon->mx != x || mon->my != y) {
265                 if (glyph_is_invisible(levl[x][y].glyph)) {
266                     unmap_object(x, y);
267                     newsym(x, y);
268                 }
269                 pline("%s %s, %s evading your %skick.", Monnam(mon),
270                       (!level.flags.noteleport && can_teleport(mon->data))
271                           ? "teleports"
272                           : is_floater(mon->data)
273                                 ? "floats"
274                                 : is_flyer(mon->data) ? "swoops"
275                                                       : (nolimbs(mon->data)
276                                                          || slithy(mon->data))
277                                                             ? "slides"
278                                                             : "jumps",
279                       clumsy ? "easily" : "nimbly", clumsy ? "clumsy " : "");
280                 (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
281                 return;
282             }
283         }
284     }
285     kickdmg(mon, clumsy);
286 }
287
288 /*
289  *  Return TRUE if caught (the gold taken care of), FALSE otherwise.
290  *  The gold object is *not* attached to the fobj chain!
291  */
292 boolean
293 ghitm(mtmp, gold)
294 register struct monst *mtmp;
295 register struct obj *gold;
296 {
297     boolean msg_given = FALSE;
298
299     if (!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest
300         && !mtmp->isgd && !is_mercenary(mtmp->data)) {
301         wakeup(mtmp);
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));
307             msg_given = TRUE;
308         }
309     } else {
310         long umoney, value = gold->quan * objects[gold->otyp].oc_cost;
311
312         mtmp->msleeping = 0;
313         finish_meating(mtmp);
314         if (!mtmp->isgd && !rn2(4)) /* not always pleasing */
315             setmangry(mtmp);
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 */
321         if (mtmp->isshk) {
322             long robbed = ESHK(mtmp)->robbed;
323
324             if (robbed) {
325                 robbed -= value;
326                 if (robbed < 0L)
327                     robbed = 0L;
328                 pline_The("amount %scovers %s recent losses.",
329                           !robbed ? "" : "partially ", mhis(mtmp));
330                 ESHK(mtmp)->robbed = robbed;
331                 if (!robbed)
332                     make_happy_shk(mtmp, FALSE);
333             } else {
334                 if (mtmp->mpeaceful) {
335                     ESHK(mtmp)->credit += value;
336                     You("have %ld %s in credit.", ESHK(mtmp)->credit,
337                         currency(ESHK(mtmp)->credit));
338                 } else
339                     verbalize("Thanks, scum!");
340             }
341         } else if (mtmp->ispriest) {
342             if (mtmp->mpeaceful)
343                 verbalize("Thank you for your contribution.");
344             else
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. */
353             verbalize(
354                 umoney
355                     ? "Drop the rest and follow me."
356                     : hidden_gold()
357                           ? "You still have hidden gold.  Drop it now."
358                           : mtmp->mpeaceful
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)) {
362             long goldreqd = 0L;
363
364             if (rn2(3)) {
365                 if (mtmp->data == &mons[PM_SOLDIER])
366                     goldreqd = 100L;
367                 else if (mtmp->data == &mons[PM_SERGEANT])
368                     goldreqd = 250L;
369                 else if (mtmp->data == &mons[PM_LIEUTENANT])
370                     goldreqd = 500L;
371                 else if (mtmp->data == &mons[PM_CAPTAIN])
372                     goldreqd = 750L;
373
374                 if (goldreqd) {
375                     umoney = money_cnt(invent);
376                     if (value
377                         > goldreqd
378                               + (umoney + u.ulevel * rn2(5)) / ACURR(A_CHA))
379                         mtmp->mpeaceful = TRUE;
380                 }
381             }
382             if (mtmp->mpeaceful)
383                 verbalize("That should do.  Now beat it!");
384             else
385                 verbalize("That's not enough, coward!");
386         }
387         return TRUE;
388     }
389
390     if (!msg_given)
391         miss(xname(gold), mtmp);
392     return FALSE;
393 }
394
395 /* container is kicked, dropped, thrown or otherwise impacted by player.
396  * Assumes container is on floor.  Checks contents for possible damage. */
397 void
398 container_impact_dmg(obj, x, y)
399 struct obj *obj;
400 xchar x, y; /* coordinates where object was before the impact, not after */
401 {
402     struct monst *shkp;
403     struct obj *otmp, *otmp2;
404     long loss = 0L;
405     boolean costly, insider, frominv;
406
407     /* only consider normal containers */
408     if (!Is_container(obj) || !Has_contents(obj) || Is_mbag(obj))
409         return;
410
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);
417
418     for (otmp = obj->cobj; otmp; otmp = otmp2) {
419         const char *result = (char *) 0;
420
421         otmp2 = otmp->nobj;
422         if (objects[otmp->otyp].oc_material == GLASS
423             && otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) {
424             result = "shatter";
425         } else if (otmp->otyp == EGG && !rn2(3)) {
426             result = "cracking";
427         }
428         if (result) {
429             if (otmp->otyp == MIRROR)
430                 change_luck(-2);
431
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)
435                 change_luck(-1);
436             You_hear("a muffled %s.", result);
437             if (costly) {
438                 if (frominv && !otmp->unpaid)
439                     otmp->no_charge = 1;
440                 loss +=
441                     stolen_value(otmp, x, y, (boolean) shkp->mpeaceful, TRUE);
442             }
443             if (otmp->quan > 1L) {
444                 useup(otmp);
445             } else {
446                 obj_extract_self(otmp);
447                 obfree(otmp, (struct obj *) 0);
448             }
449             /* contents of this container are no longer known */
450             obj->cknown = 0;
451         }
452     }
453     if (costly && loss) {
454         if (!insider) {
455             You("caused %ld %s worth of damage!", loss, currency(loss));
456             make_angry_shk(shkp, x, y);
457         } else {
458             You("owe %s %ld %s for objects destroyed.", mon_nam(shkp), loss,
459                 currency(loss));
460         }
461     }
462 }
463
464 /* jacket around really_kick_object */
465 STATIC_OVL int
466 kick_object(x, y)
467 xchar x, y;
468 {
469     int res = 0;
470
471     /* if a pile, the "top" object gets kicked */
472     kickedobj = level.objects[x][y];
473     if (kickedobj) {
474         /* kick object; if doing is fatal, done() will clean up kickedobj */
475         res = really_kick_object(x, y);
476         kickedobj = (struct obj *) 0;
477     }
478     return res;
479 }
480
481 /* guts of kick_object */
482 STATIC_OVL int
483 really_kick_object(x, y)
484 xchar x, y;
485 {
486     int range;
487     struct monst *mon, *shkp = 0;
488     struct trap *trap;
489     char bhitroom;
490     boolean costly, isgold, slide = FALSE;
491
492     /* kickedobj should always be set due to conditions of call */
493     if (!kickedobj || kickedobj->otyp == BOULDER || kickedobj == uball
494         || kickedobj == uchain)
495         return 0;
496
497     if ((trap = t_at(x, y)) != 0
498         && (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls)
499             || trap->ttyp == WEB)) {
500         if (!trap->tseen)
501             find_trap(trap);
502         You_cant("kick %s that's in a %s!", something,
503                  Hallucination ? "tizzy" : (trap->ttyp == WEB) ? "web"
504                                                                : "pit");
505         return 1;
506     }
507
508     if (Fumbling && !rn2(3)) {
509         Your("clumsy kick missed.");
510         return 1;
511     }
512
513     if (!uarmf && kickedobj->otyp == CORPSE
514         && touch_petrifies(&mons[kickedobj->corpsenm]) && !Stone_resistance) {
515         You("kick %s with your bare %s.",
516             corpse_xname(kickedobj, (const char *) 0, CXN_PFX_THE),
517             makeplural(body_part(FOOT)));
518         if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
519             ; /* hero has been transformed but kick continues */
520         } else {
521             /* normalize body shape here; foot, not body_part(FOOT) */
522             Sprintf(killer.name, "kicking %s barefoot",
523                     killer_xname(kickedobj));
524             instapetrify(killer.name);
525         }
526     }
527
528     /* range < 2 means the object will not move.  */
529     /* maybe dexterity should also figure here.   */
530     range = (int) ((ACURRSTR) / 2 - kickedobj->owt / 40);
531
532     if (martial())
533         range += rnd(3);
534
535     if (is_pool(x, y)) {
536         /* you're in the water too; significantly reduce range */
537         range = range / 3 + 1; /* {1,2}=>1, {3,4,5}=>2, {6,7,8}=>3 */
538     } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
539         /* you're in air, since is_pool did not match */
540         range += rnd(3);
541     } else {
542         if (is_ice(x, y))
543             range += rnd(3), slide = TRUE;
544         if (kickedobj->greased)
545             range += rnd(3), slide = TRUE;
546     }
547
548     /* Mjollnir is magically too heavy to kick */
549     if (kickedobj->oartifact == ART_MJOLLNIR)
550         range = 1;
551
552     /* see if the object has a place to move into */
553     if (!ZAP_POS(levl[x + u.dx][y + u.dy].typ)
554         || closed_door(x + u.dx, y + u.dy))
555         range = 1;
556
557     costly = (!(kickedobj->no_charge && !Has_contents(kickedobj))
558               && (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0
559               && costly_spot(x, y));
560     isgold = (kickedobj->oclass == COIN_CLASS);
561
562     if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
563         if ((!martial() && rn2(20) > ACURR(A_DEX))
564             || IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) {
565             if (Blind)
566                 pline("It doesn't come loose.");
567             else
568                 pline("%s %sn't come loose.",
569                       The(distant_name(kickedobj, xname)),
570                       otense(kickedobj, "do"));
571             return (!rn2(3) || martial());
572         }
573         if (Blind)
574             pline("It comes loose.");
575         else
576             pline("%s %s loose.", The(distant_name(kickedobj, xname)),
577                   otense(kickedobj, "come"));
578         obj_extract_self(kickedobj);
579         newsym(x, y);
580         if (costly && (!costly_spot(u.ux, u.uy)
581                        || !index(u.urooms, *in_rooms(x, y, SHOPBASE))))
582             addtobill(kickedobj, FALSE, FALSE, FALSE);
583         if (!flooreffects(kickedobj, u.ux, u.uy, "fall")) {
584             place_object(kickedobj, u.ux, u.uy);
585             stackobj(kickedobj);
586             newsym(u.ux, u.uy);
587         }
588         return 1;
589     }
590
591     /* a box gets a chance of breaking open here */
592     if (Is_box(kickedobj)) {
593         boolean otrp = kickedobj->otrapped;
594
595         if (range < 2)
596             pline("THUD!");
597         container_impact_dmg(kickedobj, x, y);
598         if (kickedobj->olocked) {
599             if (!rn2(5) || (martial() && !rn2(2))) {
600                 You("break open the lock!");
601                 breakchestlock(kickedobj, FALSE);
602                 if (otrp)
603                     (void) chest_trap(kickedobj, LEG, FALSE);
604                 return 1;
605             }
606         } else {
607             if (!rn2(3) || (martial() && !rn2(2))) {
608                 pline_The("lid slams open, then falls shut.");
609                 kickedobj->lknown = 1;
610                 if (otrp)
611                     (void) chest_trap(kickedobj, LEG, FALSE);
612                 return 1;
613             }
614         }
615         if (range < 2)
616             return 1;
617         /* else let it fall through to the next cases... */
618     }
619
620     /* fragile objects should not be kicked */
621     if (hero_breaks(kickedobj, kickedobj->ox, kickedobj->oy, FALSE))
622         return 1;
623
624     /* too heavy to move.  range is calculated as potential distance from
625      * player, so range == 2 means the object may move up to one square
626      * from its current position
627      */
628     if (range < 2) {
629         if (!Is_box(kickedobj))
630             pline("Thump!");
631         return (!rn2(3) || martial());
632     }
633
634     if (kickedobj->quan > 1L) {
635         if (!isgold) {
636             kickedobj = splitobj(kickedobj, 1L);
637         } else {
638             if (rn2(20)) {
639                 static NEARDATA const char *const flyingcoinmsg[] = {
640                     "scatter the coins", "knock coins all over the place",
641                     "send coins flying in all directions",
642                 };
643
644                 pline("Thwwpingg!");
645                 You("%s!", flyingcoinmsg[rn2(SIZE(flyingcoinmsg))]);
646                 (void) scatter(x, y, rn2(3) + 1, VIS_EFFECTS | MAY_HIT,
647                                kickedobj);
648                 newsym(x, y);
649                 return 1;
650             }
651             if (kickedobj->quan > 300L) {
652                 pline("Thump!");
653                 return (!rn2(3) || martial());
654             }
655         }
656     }
657
658     if (slide && !Blind)
659         pline("Whee!  %s %s across the %s.", Doname2(kickedobj),
660               otense(kickedobj, "slide"), surface(x, y));
661
662     if (costly && !isgold)
663         addtobill(kickedobj, FALSE, FALSE, TRUE);
664     obj_extract_self(kickedobj);
665     (void) snuff_candle(kickedobj);
666     newsym(x, y);
667     mon = bhit(u.dx, u.dy, range, KICKED_WEAPON,
668                (int FDECL((*), (MONST_P, OBJ_P))) 0,
669                (int FDECL((*), (OBJ_P, OBJ_P))) 0, &kickedobj);
670     if (!kickedobj)
671         return 1; /* object broken */
672
673     if (mon) {
674         if (mon->isshk && kickedobj->where == OBJ_MINVENT
675             && kickedobj->ocarry == mon)
676             return 1; /* alert shk caught it */
677         notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
678         if (isgold ? ghitm(mon, kickedobj)      /* caught? */
679                    : thitmonst(mon, kickedobj)) /* hit && used up? */
680             return 1;
681     }
682
683     /* the object might have fallen down a hole;
684        ship_object() will have taken care of shop billing */
685     if (kickedobj->where == OBJ_MIGRATING)
686         return 1;
687
688     bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE);
689     if (costly && (!costly_spot(bhitpos.x, bhitpos.y)
690                    || *in_rooms(x, y, SHOPBASE) != bhitroom)) {
691         if (isgold)
692             costly_gold(x, y, kickedobj->quan);
693         else
694             (void) stolen_value(kickedobj, x, y, (boolean) shkp->mpeaceful,
695                                 FALSE);
696     }
697
698     if (flooreffects(kickedobj, bhitpos.x, bhitpos.y, "fall"))
699         return 1;
700     if (kickedobj->unpaid)
701         subfrombill(kickedobj, shkp);
702     place_object(kickedobj, bhitpos.x, bhitpos.y);
703     stackobj(kickedobj);
704     newsym(kickedobj->ox, kickedobj->oy);
705     return 1;
706 }
707
708 /* cause of death if kicking kills kicker */
709 STATIC_OVL char *
710 kickstr(buf)
711 char *buf;
712 {
713     const char *what;
714
715     if (kickedobj)
716         what = killer_xname(kickedobj);
717     else if (maploc == &nowhere)
718         what = "nothing";
719     else if (IS_DOOR(maploc->typ))
720         what = "a door";
721     else if (IS_TREE(maploc->typ))
722         what = "a tree";
723     else if (IS_STWALL(maploc->typ))
724         what = "a wall";
725     else if (IS_ROCK(maploc->typ))
726         what = "a rock";
727     else if (IS_THRONE(maploc->typ))
728         what = "a throne";
729     else if (IS_FOUNTAIN(maploc->typ))
730         what = "a fountain";
731     else if (IS_GRAVE(maploc->typ))
732         what = "a headstone";
733     else if (IS_SINK(maploc->typ))
734         what = "a sink";
735     else if (IS_ALTAR(maploc->typ))
736         what = "an altar";
737     else if (IS_DRAWBRIDGE(maploc->typ))
738         what = "a drawbridge";
739     else if (maploc->typ == STAIRS)
740         what = "the stairs";
741     else if (maploc->typ == LADDER)
742         what = "a ladder";
743     else if (maploc->typ == IRONBARS)
744         what = "an iron bar";
745     else
746         what = "something weird";
747     return strcat(strcpy(buf, "kicking "), what);
748 }
749
750 int
751 dokick()
752 {
753     int x, y;
754     int avrg_attrib;
755     int dmg = 0, glyph, oldglyph = -1;
756     register struct monst *mtmp;
757     boolean no_kick = FALSE;
758     char buf[BUFSZ];
759
760     if (nolimbs(youmonst.data) || slithy(youmonst.data)) {
761         You("have no legs to kick with.");
762         no_kick = TRUE;
763     } else if (verysmall(youmonst.data)) {
764         You("are too small to do any kicking.");
765         no_kick = TRUE;
766     } else if (u.usteed) {
767         if (yn_function("Kick your steed?", ynchars, 'y') == 'y') {
768             You("kick %s.", mon_nam(u.usteed));
769             kick_steed();
770             return 1;
771         } else {
772             return 0;
773         }
774     } else if (Wounded_legs) {
775         /* note: jump() has similar code */
776         long wl = (EWounded_legs & BOTH_SIDES);
777         const char *bp = body_part(LEG);
778
779         if (wl == BOTH_SIDES)
780             bp = makeplural(bp);
781         Your("%s%s %s in no shape for kicking.",
782              (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "",
783              bp, (wl == BOTH_SIDES) ? "are" : "is");
784         no_kick = TRUE;
785     } else if (near_capacity() > SLT_ENCUMBER) {
786         Your("load is too heavy to balance yourself for a kick.");
787         no_kick = TRUE;
788     } else if (youmonst.data->mlet == S_LIZARD) {
789         Your("legs cannot kick effectively.");
790         no_kick = TRUE;
791     } else if (u.uinwater && !rn2(2)) {
792         Your("slow motion kick doesn't hit anything.");
793         no_kick = TRUE;
794     } else if (u.utrap) {
795         no_kick = TRUE;
796         switch (u.utraptype) {
797         case TT_PIT:
798             if (!Passes_walls)
799                 pline("There's not enough room to kick down here.");
800             else
801                 no_kick = FALSE;
802             break;
803         case TT_WEB:
804         case TT_BEARTRAP:
805             You_cant("move your %s!", body_part(LEG));
806             break;
807         default:
808             break;
809         }
810     }
811
812     if (no_kick) {
813         /* ignore direction typed before player notices kick failed */
814         display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
815         return 0;
816     }
817
818     if (!getdir((char *) 0))
819         return 0;
820     if (!u.dx && !u.dy)
821         return 0;
822
823     x = u.ux + u.dx;
824     y = u.uy + u.dy;
825
826     /* KMH -- Kicking boots always succeed */
827     if (uarmf && uarmf->otyp == KICKING_BOOTS)
828         avrg_attrib = 99;
829     else
830         avrg_attrib = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3;
831
832     if (u.uswallow) {
833         switch (rn2(3)) {
834         case 0:
835             You_cant("move your %s!", body_part(LEG));
836             break;
837         case 1:
838             if (is_animal(u.ustuck->data)) {
839                 pline("%s burps loudly.", Monnam(u.ustuck));
840                 break;
841             }
842         default:
843             Your("feeble kick has no effect.");
844             break;
845         }
846         return 1;
847     } else if (u.utrap && u.utraptype == TT_PIT) {
848         /* must be Passes_walls */
849         You("kick at the side of the pit.");
850         return 1;
851     }
852     if (Levitation) {
853         int xx, yy;
854
855         xx = u.ux - u.dx;
856         yy = u.uy - u.dy;
857         /* doors can be opened while levitating, so they must be
858          * reachable for bracing purposes
859          * Possible extension: allow bracing against stuff on the side?
860          */
861         if (isok(xx, yy) && !IS_ROCK(levl[xx][yy].typ)
862             && !IS_DOOR(levl[xx][yy].typ)
863             && (!Is_airlevel(&u.uz) || !OBJ_AT(xx, yy))) {
864             You("have nothing to brace yourself against.");
865             return 0;
866         }
867     }
868
869     mtmp = isok(x, y) ? m_at(x, y) : 0;
870     /* might not kick monster if it is hidden and becomes revealed,
871        if it is peaceful and player declines to attack, or if the
872        hero passes out due to encumbrance with low hp; context.move
873        will be 1 unless player declines to kick peaceful monster */
874     if (mtmp) {
875         oldglyph = glyph_at(x, y);
876         if (!maybe_kick_monster(mtmp, x, y))
877             return context.move;
878     }
879
880     wake_nearby();
881     u_wipe_engr(2);
882
883     if (!isok(x, y)) {
884         maploc = &nowhere;
885         goto ouch;
886     }
887     maploc = &levl[x][y];
888
889     /*
890      * The next five tests should stay in their present order:
891      * monsters, pools, objects, non-doors, doors.
892      *
893      * [FIXME:  Monsters who are hidden underneath objects or
894      * in pools should lead to hero kicking the concealment
895      * rather than the monster, probably exposing the hidden
896      * monster in the process.  And monsters who are hidden on
897      * ceiling shouldn't be kickable (unless hero is flying?);
898      * kicking toward them should just target whatever is on
899      * the floor at that spot.]
900      */
901
902     if (mtmp) {
903         /* save mtmp->data (for recoil) in case mtmp gets killed */
904         struct permonst *mdat = mtmp->data;
905
906         kick_monster(mtmp, x, y);
907         glyph = glyph_at(x, y);
908         /* see comment in attack_checks() */
909         if (mtmp->mhp <= 0) { /* DEADMONSTER() */
910             /* if we mapped an invisible monster and immediately
911                killed it, we don't want to forget what we thought
912                was there before the kick */
913             if (glyph != oldglyph && glyph_is_invisible(glyph))
914                 show_glyph(x, y, oldglyph);
915         } else if (!canspotmon(mtmp)
916                    /* check <x,y>; monster that evades kick by jumping
917                       to an unseen square doesn't leave an I behind */
918                    && mtmp->mx == x && mtmp->my == y
919                    && !glyph_is_invisible(glyph)
920                    && !(u.uswallow && mtmp == u.ustuck)) {
921             map_invisible(x, y);
922         }
923         /* recoil if floating */
924         if ((Is_airlevel(&u.uz) || Levitation) && context.move) {
925             int range;
926
927             range =
928                 ((int) youmonst.data->cwt + (weight_cap() + inv_weight()));
929             if (range < 1)
930                 range = 1; /* divide by zero avoidance */
931             range = (3 * (int) mdat->cwt) / range;
932
933             if (range < 1)
934                 range = 1;
935             hurtle(-u.dx, -u.dy, range, TRUE);
936         }
937         return 1;
938     }
939     if (glyph_is_invisible(levl[x][y].glyph)) {
940         unmap_object(x, y);
941         newsym(x, y);
942     }
943     if (is_pool(x, y) ^ !!u.uinwater) {
944         /* objects normally can't be removed from water by kicking */
945         You("splash some water around.");
946         return 1;
947     }
948
949     if (OBJ_AT(x, y) && (!Levitation || Is_airlevel(&u.uz)
950                          || Is_waterlevel(&u.uz) || sobj_at(BOULDER, x, y))) {
951         if (kick_object(x, y)) {
952             if (Is_airlevel(&u.uz))
953                 hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */
954             return 1;
955         }
956         goto ouch;
957     }
958
959     if (!IS_DOOR(maploc->typ)) {
960         if (maploc->typ == SDOOR) {
961             if (!Levitation && rn2(30) < avrg_attrib) {
962                 cvt_sdoor_to_door(maploc); /* ->typ = DOOR */
963                 pline("Crash!  %s a secret door!",
964                       /* don't "kick open" when it's locked
965                          unless it also happens to be trapped */
966                       (maploc->doormask & (D_LOCKED | D_TRAPPED)) == D_LOCKED
967                           ? "Your kick uncovers"
968                           : "You kick open");
969                 exercise(A_DEX, TRUE);
970                 if (maploc->doormask & D_TRAPPED) {
971                     maploc->doormask = D_NODOOR;
972                     b_trapped("door", FOOT);
973                 } else if (maploc->doormask != D_NODOOR
974                            && !(maploc->doormask & D_LOCKED))
975                     maploc->doormask = D_ISOPEN;
976                 feel_newsym(x, y); /* we know it's gone */
977                 if (maploc->doormask == D_ISOPEN
978                     || maploc->doormask == D_NODOOR)
979                     unblock_point(x, y); /* vision */
980                 return 1;
981             } else
982                 goto ouch;
983         }
984         if (maploc->typ == SCORR) {
985             if (!Levitation && rn2(30) < avrg_attrib) {
986                 pline("Crash!  You kick open a secret passage!");
987                 exercise(A_DEX, TRUE);
988                 maploc->typ = CORR;
989                 feel_newsym(x, y); /* we know it's gone */
990                 unblock_point(x, y); /* vision */
991                 return 1;
992             } else
993                 goto ouch;
994         }
995         if (IS_THRONE(maploc->typ)) {
996             register int i;
997             if (Levitation)
998                 goto dumb;
999             if ((Luck < 0 || maploc->doormask) && !rn2(3)) {
1000                 maploc->typ = ROOM;
1001                 maploc->doormask = 0; /* don't leave loose ends.. */
1002                 (void) mkgold((long) rnd(200), x, y);
1003                 if (Blind)
1004                     pline("CRASH!  You destroy it.");
1005                 else {
1006                     pline("CRASH!  You destroy the throne.");
1007                     newsym(x, y);
1008                 }
1009                 exercise(A_DEX, TRUE);
1010                 return 1;
1011             } else if (Luck > 0 && !rn2(3) && !maploc->looted) {
1012                 (void) mkgold((long) rn1(201, 300), x, y);
1013                 i = Luck + 1;
1014                 if (i > 6)
1015                     i = 6;
1016                 while (i--)
1017                     (void) mksobj_at(
1018                         rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE - 1), x, y,
1019                         FALSE, TRUE);
1020                 if (Blind)
1021                     You("kick %s loose!", something);
1022                 else {
1023                     You("kick loose some ornamental coins and gems!");
1024                     newsym(x, y);
1025                 }
1026                 /* prevent endless milking */
1027                 maploc->looted = T_LOOTED;
1028                 return 1;
1029             } else if (!rn2(4)) {
1030                 if (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) {
1031                     fall_through(FALSE);
1032                     return 1;
1033                 } else
1034                     goto ouch;
1035             }
1036             goto ouch;
1037         }
1038         if (IS_ALTAR(maploc->typ)) {
1039             if (Levitation)
1040                 goto dumb;
1041             You("kick %s.", (Blind ? something : "the altar"));
1042             if (!rn2(3))
1043                 goto ouch;
1044             altar_wrath(x, y);
1045             exercise(A_DEX, TRUE);
1046             return 1;
1047         }
1048         if (IS_FOUNTAIN(maploc->typ)) {
1049             if (Levitation)
1050                 goto dumb;
1051             You("kick %s.", (Blind ? something : "the fountain"));
1052             if (!rn2(3))
1053                 goto ouch;
1054             /* make metal boots rust */
1055             if (uarmf && rn2(3))
1056                 if (water_damage(uarmf, "metal boots", TRUE) == ER_NOTHING) {
1057                     Your("boots get wet.");
1058                     /* could cause short-lived fumbling here */
1059                 }
1060             exercise(A_DEX, TRUE);
1061             return 1;
1062         }
1063         if (IS_GRAVE(maploc->typ)) {
1064             if (Levitation)
1065                 goto dumb;
1066             if (rn2(4))
1067                 goto ouch;
1068             exercise(A_WIS, FALSE);
1069             if (Role_if(PM_ARCHEOLOGIST) || Role_if(PM_SAMURAI)
1070                 || ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10))) {
1071                 adjalign(-sgn(u.ualign.type));
1072             }
1073             maploc->typ = ROOM;
1074             maploc->doormask = 0;
1075             (void) mksobj_at(ROCK, x, y, TRUE, FALSE);
1076             del_engr_at(x, y);
1077             if (Blind)
1078                 pline("Crack!  %s broke!", Something);
1079             else {
1080                 pline_The("headstone topples over and breaks!");
1081                 newsym(x, y);
1082             }
1083             return 1;
1084         }
1085         if (maploc->typ == IRONBARS)
1086             goto ouch;
1087         if (IS_TREE(maploc->typ)) {
1088             struct obj *treefruit;
1089             /* nothing, fruit or trouble? 75:23.5:1.5% */
1090             if (rn2(3)) {
1091                 if (!rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE))
1092                     You_hear("a low buzzing."); /* a warning */
1093                 goto ouch;
1094             }
1095             if (rn2(15) && !(maploc->looted & TREE_LOOTED)
1096                 && (treefruit = rnd_treefruit_at(x, y))) {
1097                 long nfruit = 8L - rnl(7), nfall;
1098                 short frtype = treefruit->otyp;
1099                 treefruit->quan = nfruit;
1100                 if (is_plural(treefruit))
1101                     pline("Some %s fall from the tree!", xname(treefruit));
1102                 else
1103                     pline("%s falls from the tree!", An(xname(treefruit)));
1104                 nfall = scatter(x, y, 2, MAY_HIT, treefruit);
1105                 if (nfall != nfruit) {
1106                     /* scatter left some in the tree, but treefruit
1107                      * may not refer to the correct object */
1108                     treefruit = mksobj(frtype, TRUE, FALSE);
1109                     treefruit->quan = nfruit - nfall;
1110                     pline("%ld %s got caught in the branches.",
1111                           nfruit - nfall, xname(treefruit));
1112                     dealloc_obj(treefruit);
1113                 }
1114                 exercise(A_DEX, TRUE);
1115                 exercise(A_WIS, TRUE); /* discovered a new food source! */
1116                 newsym(x, y);
1117                 maploc->looted |= TREE_LOOTED;
1118                 return 1;
1119             } else if (!(maploc->looted & TREE_SWARM)) {
1120                 int cnt = rnl(4) + 2;
1121                 int made = 0;
1122                 coord mm;
1123                 mm.x = x;
1124                 mm.y = y;
1125                 while (cnt--) {
1126                     if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE])
1127                         && makemon(&mons[PM_KILLER_BEE], mm.x, mm.y,
1128                                    MM_ANGRY))
1129                         made++;
1130                 }
1131                 if (made)
1132                     pline("You've attracted the tree's former occupants!");
1133                 else
1134                     You("smell stale honey.");
1135                 maploc->looted |= TREE_SWARM;
1136                 return 1;
1137             }
1138             goto ouch;
1139         }
1140         if (IS_SINK(maploc->typ)) {
1141             int gend = poly_gender();
1142             short washerndx = (gend == 1 || (gend == 2 && rn2(2)))
1143                                   ? PM_INCUBUS
1144                                   : PM_SUCCUBUS;
1145
1146             if (Levitation)
1147                 goto dumb;
1148             if (rn2(5)) {
1149                 if (!Deaf)
1150                     pline("Klunk!  The pipes vibrate noisily.");
1151                 else
1152                     pline("Klunk!");
1153                 exercise(A_DEX, TRUE);
1154                 return 1;
1155             } else if (!(maploc->looted & S_LPUDDING) && !rn2(3)
1156                        && !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) {
1157                 if (Blind)
1158                     You_hear("a gushing sound.");
1159                 else
1160                     pline("A %s ooze gushes up from the drain!",
1161                           hcolor(NH_BLACK));
1162                 (void) makemon(&mons[PM_BLACK_PUDDING], x, y, NO_MM_FLAGS);
1163                 exercise(A_DEX, TRUE);
1164                 newsym(x, y);
1165                 maploc->looted |= S_LPUDDING;
1166                 return 1;
1167             } else if (!(maploc->looted & S_LDWASHER) && !rn2(3)
1168                        && !(mvitals[washerndx].mvflags & G_GONE)) {
1169                 /* can't resist... */
1170                 pline("%s returns!", (Blind ? Something : "The dish washer"));
1171                 if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS))
1172                     newsym(x, y);
1173                 maploc->looted |= S_LDWASHER;
1174                 exercise(A_DEX, TRUE);
1175                 return 1;
1176             } else if (!rn2(3)) {
1177                 pline("Flupp!  %s.",
1178                       (Blind ? "You hear a sloshing sound"
1179                              : "Muddy waste pops up from the drain"));
1180                 if (!(maploc->looted & S_LRING)) { /* once per sink */
1181                     if (!Blind)
1182                         You_see("a ring shining in its midst.");
1183                     (void) mkobj_at(RING_CLASS, x, y, TRUE);
1184                     newsym(x, y);
1185                     exercise(A_DEX, TRUE);
1186                     exercise(A_WIS, TRUE); /* a discovery! */
1187                     maploc->looted |= S_LRING;
1188                 }
1189                 return 1;
1190             }
1191             goto ouch;
1192         }
1193         if (maploc->typ == STAIRS || maploc->typ == LADDER
1194             || IS_STWALL(maploc->typ)) {
1195             if (!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN)
1196                 goto dumb;
1197         ouch:
1198             pline("Ouch!  That hurts!");
1199             exercise(A_DEX, FALSE);
1200             exercise(A_STR, FALSE);
1201             if (isok(x, y)) {
1202                 if (Blind)
1203                     feel_location(x, y); /* we know we hit it */
1204                 if (is_drawbridge_wall(x, y) >= 0) {
1205                     pline_The("drawbridge is unaffected.");
1206                     /* update maploc to refer to the drawbridge */
1207                     (void) find_drawbridge(&x, &y);
1208                     maploc = &levl[x][y];
1209                 }
1210             }
1211             if (!rn2(3))
1212                 set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
1213             dmg = rnd(ACURR(A_CON) > 15 ? 3 : 5);
1214             losehp(Maybe_Half_Phys(dmg), kickstr(buf), KILLED_BY);
1215             if (Is_airlevel(&u.uz) || Levitation)
1216                 hurtle(-u.dx, -u.dy, rn1(2, 4), TRUE); /* assume it's heavy */
1217             return 1;
1218         }
1219         goto dumb;
1220     }
1221
1222     if (maploc->doormask == D_ISOPEN || maploc->doormask == D_BROKEN
1223         || maploc->doormask == D_NODOOR) {
1224     dumb:
1225         exercise(A_DEX, FALSE);
1226         if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) {
1227             You("kick at empty space.");
1228             if (Blind)
1229                 feel_location(x, y);
1230         } else {
1231             pline("Dumb move!  You strain a muscle.");
1232             exercise(A_STR, FALSE);
1233             set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
1234         }
1235         if ((Is_airlevel(&u.uz) || Levitation) && rn2(2))
1236             hurtle(-u.dx, -u.dy, 1, TRUE);
1237         return 1; /* uses a turn */
1238     }
1239
1240     /* not enough leverage to kick open doors while levitating */
1241     if (Levitation)
1242         goto ouch;
1243
1244     exercise(A_DEX, TRUE);
1245     /* door is known to be CLOSED or LOCKED */
1246     if (rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
1247         boolean shopdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE;
1248         /* break the door */
1249         if (maploc->doormask & D_TRAPPED) {
1250             if (flags.verbose)
1251                 You("kick the door.");
1252             exercise(A_STR, FALSE);
1253             maploc->doormask = D_NODOOR;
1254             b_trapped("door", FOOT);
1255         } else if (ACURR(A_STR) > 18 && !rn2(5) && !shopdoor) {
1256             pline("As you kick the door, it shatters to pieces!");
1257             exercise(A_STR, TRUE);
1258             maploc->doormask = D_NODOOR;
1259         } else {
1260             pline("As you kick the door, it crashes open!");
1261             exercise(A_STR, TRUE);
1262             maploc->doormask = D_BROKEN;
1263         }
1264         feel_newsym(x, y); /* we know we broke it */
1265         unblock_point(x, y); /* vision */
1266         if (shopdoor) {
1267             add_damage(x, y, 400L);
1268             pay_for_damage("break", FALSE);
1269         }
1270         if (in_town(x, y))
1271             for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1272                 if (DEADMONSTER(mtmp))
1273                     continue;
1274                 if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my)
1275                     && mtmp->mpeaceful) {
1276                     mon_yells(mtmp, "Halt, thief!  You're under arrest!");
1277                     (void) angry_guards(FALSE);
1278                     break;
1279                 }
1280             }
1281     } else {
1282         if (Blind)
1283             feel_location(x, y); /* we know we hit it */
1284         exercise(A_STR, TRUE);
1285         pline("WHAMMM!!!");
1286         if (in_town(x, y))
1287             for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1288                 if (DEADMONSTER(mtmp))
1289                     continue;
1290                 if (is_watch(mtmp->data) && mtmp->mpeaceful
1291                     && couldsee(mtmp->mx, mtmp->my)) {
1292                     if (levl[x][y].looted & D_WARNED) {
1293                         mon_yells(mtmp,
1294                                   "Halt, vandal!  You're under arrest!");
1295                         (void) angry_guards(FALSE);
1296                     } else {
1297                         mon_yells(mtmp, "Hey, stop damaging that door!");
1298                         levl[x][y].looted |= D_WARNED;
1299                     }
1300                     break;
1301                 }
1302             }
1303     }
1304     return 1;
1305 }
1306
1307 STATIC_OVL void
1308 drop_to(cc, loc)
1309 coord *cc;
1310 schar loc;
1311 {
1312     /* cover all the MIGR_xxx choices generated by down_gate() */
1313     switch (loc) {
1314     case MIGR_RANDOM: /* trap door or hole */
1315         if (Is_stronghold(&u.uz)) {
1316             cc->x = valley_level.dnum;
1317             cc->y = valley_level.dlevel;
1318             break;
1319         } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) {
1320             cc->y = cc->x = 0;
1321             break;
1322         } /* else fall to the next cases */
1323     case MIGR_STAIRS_UP:
1324     case MIGR_LADDER_UP:
1325         cc->x = u.uz.dnum;
1326         cc->y = u.uz.dlevel + 1;
1327         break;
1328     case MIGR_SSTAIRS:
1329         cc->x = sstairs.tolev.dnum;
1330         cc->y = sstairs.tolev.dlevel;
1331         break;
1332     default:
1333     case MIGR_NOWHERE:
1334         /* y==0 means "nowhere", in which case x doesn't matter */
1335         cc->y = cc->x = 0;
1336         break;
1337     }
1338 }
1339
1340 /* player or missile impacts location, causing objects to fall down */
1341 void
1342 impact_drop(missile, x, y, dlev)
1343 struct obj *missile; /* caused impact, won't drop itself */
1344 xchar x, y;          /* location affected */
1345 xchar dlev;          /* if !0 send to dlev near player */
1346 {
1347     schar toloc;
1348     register struct obj *obj, *obj2;
1349     register struct monst *shkp;
1350     long oct, dct, price, debit, robbed;
1351     boolean angry, costly, isrock;
1352     coord cc;
1353
1354     if (!OBJ_AT(x, y))
1355         return;
1356
1357     toloc = down_gate(x, y);
1358     drop_to(&cc, toloc);
1359     if (!cc.y)
1360         return;
1361
1362     if (dlev) {
1363         /* send objects next to player falling through trap door.
1364          * checked in obj_delivery().
1365          */
1366         toloc = MIGR_WITH_HERO;
1367         cc.y = dlev;
1368     }
1369
1370     costly = costly_spot(x, y);
1371     price = debit = robbed = 0L;
1372     angry = FALSE;
1373     shkp = (struct monst *) 0;
1374     /* if 'costly', we must keep a record of ESHK(shkp) before
1375      * it undergoes changes through the calls to stolen_value.
1376      * the angry bit must be reset, if needed, in this fn, since
1377      * stolen_value is called under the 'silent' flag to avoid
1378      * unsavory pline repetitions.
1379      */
1380     if (costly) {
1381         if ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0) {
1382             debit = ESHK(shkp)->debit;
1383             robbed = ESHK(shkp)->robbed;
1384             angry = !shkp->mpeaceful;
1385         }
1386     }
1387
1388     isrock = (missile && missile->otyp == ROCK);
1389     oct = dct = 0L;
1390     for (obj = level.objects[x][y]; obj; obj = obj2) {
1391         obj2 = obj->nexthere;
1392         if (obj == missile)
1393             continue;
1394         /* number of objects in the pile */
1395         oct += obj->quan;
1396         if (obj == uball || obj == uchain)
1397             continue;
1398         /* boulders can fall too, but rarely & never due to rocks */
1399         if ((isrock && obj->otyp == BOULDER)
1400             || rn2(obj->otyp == BOULDER ? 30 : 3))
1401             continue;
1402         obj_extract_self(obj);
1403
1404         if (costly) {
1405             price += stolen_value(
1406                 obj, x, y, (costly_spot(u.ux, u.uy)
1407                             && index(u.urooms, *in_rooms(x, y, SHOPBASE))),
1408                 TRUE);
1409             /* set obj->no_charge to 0 */
1410             if (Has_contents(obj))
1411                 picked_container(obj); /* does the right thing */
1412             if (obj->oclass != COIN_CLASS)
1413                 obj->no_charge = 0;
1414         }
1415
1416         add_to_migration(obj);
1417         obj->ox = cc.x;
1418         obj->oy = cc.y;
1419         obj->owornmask = (long) toloc;
1420
1421         /* number of fallen objects */
1422         dct += obj->quan;
1423     }
1424
1425     if (dct && cansee(x, y)) { /* at least one object fell */
1426         const char *what = (dct == 1L ? "object falls" : "objects fall");
1427
1428         if (missile)
1429             pline("From the impact, %sother %s.",
1430                   dct == oct ? "the " : dct == 1L ? "an" : "", what);
1431         else if (oct == dct)
1432             pline("%s adjacent %s %s.", dct == 1L ? "The" : "All the", what,
1433                   gate_str);
1434         else
1435             pline("%s adjacent %s %s.",
1436                   dct == 1L ? "One of the" : "Some of the",
1437                   dct == 1L ? "objects falls" : what, gate_str);
1438     }
1439
1440     if (costly && shkp && price) {
1441         if (ESHK(shkp)->robbed > robbed) {
1442             You("removed %ld %s worth of goods!", price, currency(price));
1443             if (cansee(shkp->mx, shkp->my)) {
1444                 if (ESHK(shkp)->customer[0] == 0)
1445                     (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ);
1446                 if (angry)
1447                     pline("%s is infuriated!", Monnam(shkp));
1448                 else
1449                     pline("\"%s, you are a thief!\"", plname);
1450             } else
1451                 You_hear("a scream, \"Thief!\"");
1452             hot_pursuit(shkp);
1453             (void) angry_guards(FALSE);
1454             return;
1455         }
1456         if (ESHK(shkp)->debit > debit) {
1457             long amt = (ESHK(shkp)->debit - debit);
1458             You("owe %s %ld %s for goods lost.", Monnam(shkp), amt,
1459                 currency(amt));
1460         }
1461     }
1462 }
1463
1464 /* NOTE: ship_object assumes otmp was FREED from fobj or invent.
1465  * <x,y> is the point of drop.  otmp is _not_ an <x,y> resident:
1466  * otmp is either a kicked, dropped, or thrown object.
1467  */
1468 boolean
1469 ship_object(otmp, x, y, shop_floor_obj)
1470 xchar x, y;
1471 struct obj *otmp;
1472 boolean shop_floor_obj;
1473 {
1474     schar toloc;
1475     xchar ox, oy;
1476     coord cc;
1477     struct obj *obj;
1478     struct trap *t;
1479     boolean nodrop, unpaid, container, impact = FALSE;
1480     long n = 0L;
1481
1482     if (!otmp)
1483         return FALSE;
1484     if ((toloc = down_gate(x, y)) == MIGR_NOWHERE)
1485         return FALSE;
1486     drop_to(&cc, toloc);
1487     if (!cc.y)
1488         return FALSE;
1489
1490     /* objects other than attached iron ball always fall down ladder,
1491        but have a chance of staying otherwise */
1492     nodrop = (otmp == uball) || (otmp == uchain)
1493              || (toloc != MIGR_LADDER_UP && rn2(3));
1494
1495     container = Has_contents(otmp);
1496     unpaid = is_unpaid(otmp);
1497
1498     if (OBJ_AT(x, y)) {
1499         for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
1500             if (obj != otmp)
1501                 n += obj->quan;
1502         if (n)
1503             impact = TRUE;
1504     }
1505     /* boulders never fall through trap doors, but they might knock
1506        other things down before plugging the hole */
1507     if (otmp->otyp == BOULDER && ((t = t_at(x, y)) != 0)
1508         && (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) {
1509         if (impact)
1510             impact_drop(otmp, x, y, 0);
1511         return FALSE; /* let caller finish the drop */
1512     }
1513
1514     if (cansee(x, y))
1515         otransit_msg(otmp, nodrop, n);
1516
1517     if (nodrop) {
1518         if (impact)
1519             impact_drop(otmp, x, y, 0);
1520         return FALSE;
1521     }
1522
1523     if (unpaid || shop_floor_obj) {
1524         if (unpaid) {
1525             (void) stolen_value(otmp, u.ux, u.uy, TRUE, FALSE);
1526         } else {
1527             ox = otmp->ox;
1528             oy = otmp->oy;
1529             (void) stolen_value(
1530                 otmp, ox, oy,
1531                 (costly_spot(u.ux, u.uy)
1532                  && index(u.urooms, *in_rooms(ox, oy, SHOPBASE))),
1533                 FALSE);
1534         }
1535         /* set otmp->no_charge to 0 */
1536         if (container)
1537             picked_container(otmp); /* happens to do the right thing */
1538         if (otmp->oclass != COIN_CLASS)
1539             otmp->no_charge = 0;
1540     }
1541
1542     if (otmp->owornmask)
1543         remove_worn_item(otmp, TRUE);
1544
1545     /* some things break rather than ship */
1546     if (breaktest(otmp)) {
1547         const char *result;
1548
1549         if (objects[otmp->otyp].oc_material == GLASS
1550             || otmp->otyp == EXPENSIVE_CAMERA) {
1551             if (otmp->otyp == MIRROR)
1552                 change_luck(-2);
1553             result = "crash";
1554         } else {
1555             /* penalty for breaking eggs laid by you */
1556             if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
1557                 change_luck((schar) -min(otmp->quan, 5L));
1558             result = "splat";
1559         }
1560         You_hear("a muffled %s.", result);
1561         obj_extract_self(otmp);
1562         obfree(otmp, (struct obj *) 0);
1563         return TRUE;
1564     }
1565
1566     add_to_migration(otmp);
1567     otmp->ox = cc.x;
1568     otmp->oy = cc.y;
1569     otmp->owornmask = (long) toloc;
1570     /* boulder from rolling boulder trap, no longer part of the trap */
1571     if (otmp->otyp == BOULDER)
1572         otmp->otrapped = 0;
1573
1574     if (impact) {
1575         /* the objs impacted may be in a shop other than
1576          * the one in which the hero is located.  another
1577          * check for a shk is made in impact_drop.  it is, e.g.,
1578          * possible to kick/throw an object belonging to one
1579          * shop into another shop through a gap in the wall,
1580          * and cause objects belonging to the other shop to
1581          * fall down a trap door--thereby getting two shopkeepers
1582          * angry at the hero in one shot.
1583          */
1584         impact_drop(otmp, x, y, 0);
1585         newsym(x, y);
1586     }
1587     return TRUE;
1588 }
1589
1590 void
1591 obj_delivery(near_hero)
1592 boolean near_hero;
1593 {
1594     register struct obj *otmp, *otmp2;
1595     register int nx, ny;
1596     int where;
1597     boolean nobreak, noscatter;
1598
1599     for (otmp = migrating_objs; otmp; otmp = otmp2) {
1600         otmp2 = otmp->nobj;
1601         if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel)
1602             continue;
1603
1604         where = (int) (otmp->owornmask & 0x7fffL); /* destination code */
1605         nobreak = (where & MIGR_NOBREAK) != 0;
1606         noscatter = (where & MIGR_WITH_HERO) != 0;
1607         where &= ~(MIGR_NOBREAK | MIGR_NOSCATTER);
1608
1609         if (!near_hero ^ (where == MIGR_WITH_HERO))
1610             continue;
1611
1612         obj_extract_self(otmp);
1613         otmp->owornmask = 0L;
1614
1615         switch (where) {
1616         case MIGR_STAIRS_UP:
1617             nx = xupstair, ny = yupstair;
1618             break;
1619         case MIGR_LADDER_UP:
1620             nx = xupladder, ny = yupladder;
1621             break;
1622         case MIGR_SSTAIRS:
1623             nx = sstairs.sx, ny = sstairs.sy;
1624             break;
1625         case MIGR_WITH_HERO:
1626             nx = u.ux, ny = u.uy;
1627             break;
1628         default:
1629         case MIGR_RANDOM:
1630             nx = ny = 0;
1631             break;
1632         }
1633         if (nx > 0) {
1634             place_object(otmp, nx, ny);
1635             if (!nobreak && !IS_SOFT(levl[nx][ny].typ)) {
1636                 if (where == MIGR_WITH_HERO) {
1637                     if (breaks(otmp, nx, ny))
1638                         continue;
1639                 } else if (breaktest(otmp)) {
1640                     /* assume it broke before player arrived, no messages */
1641                     delobj(otmp);
1642                     continue;
1643                 }
1644             }
1645             stackobj(otmp);
1646             if (!noscatter)
1647                 (void) scatter(nx, ny, rnd(2), 0, otmp);
1648         } else { /* random location */
1649             /* set dummy coordinates because there's no
1650                current position for rloco() to update */
1651             otmp->ox = otmp->oy = 0;
1652             if (rloco(otmp) && !nobreak && breaktest(otmp)) {
1653                 /* assume it broke before player arrived, no messages */
1654                 delobj(otmp);
1655             }
1656         }
1657     }
1658 }
1659
1660 STATIC_OVL void
1661 otransit_msg(otmp, nodrop, num)
1662 register struct obj *otmp;
1663 register boolean nodrop;
1664 long num;
1665 {
1666     char obuf[BUFSZ];
1667
1668     Sprintf(obuf, "%s%s",
1669             (otmp->otyp == CORPSE && type_is_pname(&mons[otmp->corpsenm]))
1670                 ? ""
1671                 : "The ",
1672             cxname(otmp));
1673
1674     if (num) { /* means: other objects are impacted */
1675         Sprintf(eos(obuf), " %s %s object%s", otense(otmp, "hit"),
1676                 num == 1L ? "another" : "other", num > 1L ? "s" : "");
1677         if (nodrop)
1678             Sprintf(eos(obuf), ".");
1679         else
1680             Sprintf(eos(obuf), " and %s %s.", otense(otmp, "fall"), gate_str);
1681         pline1(obuf);
1682     } else if (!nodrop)
1683         pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str);
1684 }
1685
1686 /* migration destination for objects which fall down to next level */
1687 schar
1688 down_gate(x, y)
1689 xchar x, y;
1690 {
1691     struct trap *ttmp;
1692
1693     gate_str = 0;
1694     /* this matches the player restriction in goto_level() */
1695     if (on_level(&u.uz, &qstart_level) && !ok_to_quest())
1696         return MIGR_NOWHERE;
1697
1698     if ((xdnstair == x && ydnstair == y)
1699         || (sstairs.sx == x && sstairs.sy == y && !sstairs.up)) {
1700         gate_str = "down the stairs";
1701         return (xdnstair == x && ydnstair == y) ? MIGR_STAIRS_UP
1702                                                 : MIGR_SSTAIRS;
1703     }
1704     if (xdnladder == x && ydnladder == y) {
1705         gate_str = "down the ladder";
1706         return MIGR_LADDER_UP;
1707     }
1708
1709     if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen)
1710         && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) {
1711         gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door"
1712                                             : "through the hole";
1713         return MIGR_RANDOM;
1714     }
1715     return MIGR_NOWHERE;
1716 }
1717
1718 /*dokick.c*/