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));
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));
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 */
471 /* if a pile, the "top" object gets kicked */
472 kickedobj = level.objects[x][y];
474 /* kick object; if doing is fatal, done() will clean up kickedobj */
475 res = really_kick_object(x, y);
476 kickedobj = (struct obj *) 0;
481 /* guts of kick_object */
483 really_kick_object(x, y)
487 struct monst *mon, *shkp = 0;
490 boolean costly, isgold, slide = FALSE;
492 /* kickedobj should always be set due to conditions of call */
493 if (!kickedobj || kickedobj->otyp == BOULDER || kickedobj == uball
494 || kickedobj == uchain)
497 if ((trap = t_at(x, y)) != 0
498 && (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls)
499 || trap->ttyp == WEB)) {
502 You_cant("kick %s that's in a %s!", something,
503 Hallucination ? "tizzy" : (trap->ttyp == WEB) ? "web"
508 if (Fumbling && !rn2(3)) {
509 Your("clumsy kick missed.");
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 */
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);
528 /* range < 2 means the object will not move. */
529 /* maybe dexterity should also figure here. */
530 range = (int) ((ACURRSTR) / 2 - kickedobj->owt / 40);
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 */
543 range += rnd(3), slide = TRUE;
544 if (kickedobj->greased)
545 range += rnd(3), slide = TRUE;
548 /* Mjollnir is magically too heavy to kick */
549 if (kickedobj->oartifact == ART_MJOLLNIR)
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))
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);
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)) {
566 pline("It doesn't come loose.");
568 pline("%s %sn't come loose.",
569 The(distant_name(kickedobj, xname)),
570 otense(kickedobj, "do"));
571 return (!rn2(3) || martial());
574 pline("It comes loose.");
576 pline("%s %s loose.", The(distant_name(kickedobj, xname)),
577 otense(kickedobj, "come"));
578 obj_extract_self(kickedobj);
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);
591 /* a box gets a chance of breaking open here */
592 if (Is_box(kickedobj)) {
593 boolean otrp = kickedobj->otrapped;
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);
603 (void) chest_trap(kickedobj, LEG, FALSE);
607 if (!rn2(3) || (martial() && !rn2(2))) {
608 pline_The("lid slams open, then falls shut.");
609 kickedobj->lknown = 1;
611 (void) chest_trap(kickedobj, LEG, FALSE);
617 /* else let it fall through to the next cases... */
620 /* fragile objects should not be kicked */
621 if (hero_breaks(kickedobj, kickedobj->ox, kickedobj->oy, FALSE))
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
629 if (!Is_box(kickedobj))
631 return (!rn2(3) || martial());
634 if (kickedobj->quan > 1L) {
636 kickedobj = splitobj(kickedobj, 1L);
639 static NEARDATA const char *const flyingcoinmsg[] = {
640 "scatter the coins", "knock coins all over the place",
641 "send coins flying in all directions",
645 You("%s!", flyingcoinmsg[rn2(SIZE(flyingcoinmsg))]);
646 (void) scatter(x, y, rn2(3) + 1, VIS_EFFECTS | MAY_HIT,
651 if (kickedobj->quan > 300L) {
653 return (!rn2(3) || martial());
659 pline("Whee! %s %s across the %s.", Doname2(kickedobj),
660 otense(kickedobj, "slide"), surface(x, y));
662 if (costly && !isgold)
663 addtobill(kickedobj, FALSE, FALSE, TRUE);
664 obj_extract_self(kickedobj);
665 (void) snuff_candle(kickedobj);
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);
671 return 1; /* object broken */
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? */
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)
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)) {
692 costly_gold(x, y, kickedobj->quan);
694 (void) stolen_value(kickedobj, x, y, (boolean) shkp->mpeaceful,
698 if (flooreffects(kickedobj, bhitpos.x, bhitpos.y, "fall"))
700 if (kickedobj->unpaid)
701 subfrombill(kickedobj, shkp);
702 place_object(kickedobj, bhitpos.x, bhitpos.y);
704 newsym(kickedobj->ox, kickedobj->oy);
708 /* cause of death if kicking kills kicker */
716 what = killer_xname(kickedobj);
717 else if (maploc == &nowhere)
719 else if (IS_DOOR(maploc->typ))
721 else if (IS_TREE(maploc->typ))
723 else if (IS_STWALL(maploc->typ))
725 else if (IS_ROCK(maploc->typ))
727 else if (IS_THRONE(maploc->typ))
729 else if (IS_FOUNTAIN(maploc->typ))
731 else if (IS_GRAVE(maploc->typ))
732 what = "a headstone";
733 else if (IS_SINK(maploc->typ))
735 else if (IS_ALTAR(maploc->typ))
737 else if (IS_DRAWBRIDGE(maploc->typ))
738 what = "a drawbridge";
739 else if (maploc->typ == STAIRS)
741 else if (maploc->typ == LADDER)
743 else if (maploc->typ == IRONBARS)
744 what = "an iron bar";
746 what = "something weird";
747 return strcat(strcpy(buf, "kicking "), what);
755 int dmg = 0, glyph, oldglyph = -1;
756 register struct monst *mtmp;
757 boolean no_kick = FALSE;
760 if (nolimbs(youmonst.data) || slithy(youmonst.data)) {
761 You("have no legs to kick with.");
763 } else if (verysmall(youmonst.data)) {
764 You("are too small to do any kicking.");
766 } else if (u.usteed) {
767 if (yn_function("Kick your steed?", ynchars, 'y') == 'y') {
768 You("kick %s.", mon_nam(u.usteed));
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);
779 if (wl == BOTH_SIDES)
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");
785 } else if (near_capacity() > SLT_ENCUMBER) {
786 Your("load is too heavy to balance yourself for a kick.");
788 } else if (youmonst.data->mlet == S_LIZARD) {
789 Your("legs cannot kick effectively.");
791 } else if (u.uinwater && !rn2(2)) {
792 Your("slow motion kick doesn't hit anything.");
794 } else if (u.utrap) {
796 switch (u.utraptype) {
799 pline("There's not enough room to kick down here.");
805 You_cant("move your %s!", body_part(LEG));
813 /* ignore direction typed before player notices kick failed */
814 display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
818 if (!getdir((char *) 0))
826 /* KMH -- Kicking boots always succeed */
827 if (uarmf && uarmf->otyp == KICKING_BOOTS)
830 avrg_attrib = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3;
835 You_cant("move your %s!", body_part(LEG));
838 if (is_animal(u.ustuck->data)) {
839 pline("%s burps loudly.", Monnam(u.ustuck));
843 Your("feeble kick has no effect.");
847 } else if (u.utrap && u.utraptype == TT_PIT) {
848 /* must be Passes_walls */
849 You("kick at the side of the pit.");
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?
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.");
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 */
875 oldglyph = glyph_at(x, y);
876 if (!maybe_kick_monster(mtmp, x, y))
887 maploc = &levl[x][y];
890 * The next five tests should stay in their present order:
891 * monsters, pools, objects, non-doors, doors.
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.]
903 /* save mtmp->data (for recoil) in case mtmp gets killed */
904 struct permonst *mdat = mtmp->data;
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)) {
923 /* recoil if floating */
924 if ((Is_airlevel(&u.uz) || Levitation) && context.move) {
928 ((int) youmonst.data->cwt + (weight_cap() + inv_weight()));
930 range = 1; /* divide by zero avoidance */
931 range = (3 * (int) mdat->cwt) / range;
935 hurtle(-u.dx, -u.dy, range, TRUE);
939 if (glyph_is_invisible(levl[x][y].glyph)) {
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.");
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 */
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"
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 */
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);
989 feel_newsym(x, y); /* we know it's gone */
990 unblock_point(x, y); /* vision */
995 if (IS_THRONE(maploc->typ)) {
999 if ((Luck < 0 || maploc->doormask) && !rn2(3)) {
1001 maploc->doormask = 0; /* don't leave loose ends.. */
1002 (void) mkgold((long) rnd(200), x, y);
1004 pline("CRASH! You destroy it.");
1006 pline("CRASH! You destroy the throne.");
1009 exercise(A_DEX, TRUE);
1011 } else if (Luck > 0 && !rn2(3) && !maploc->looted) {
1012 (void) mkgold((long) rn1(201, 300), x, y);
1018 rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE - 1), x, y,
1021 You("kick %s loose!", something);
1023 You("kick loose some ornamental coins and gems!");
1026 /* prevent endless milking */
1027 maploc->looted = T_LOOTED;
1029 } else if (!rn2(4)) {
1030 if (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) {
1031 fall_through(FALSE);
1038 if (IS_ALTAR(maploc->typ)) {
1041 You("kick %s.", (Blind ? something : "the altar"));
1045 exercise(A_DEX, TRUE);
1048 if (IS_FOUNTAIN(maploc->typ)) {
1051 You("kick %s.", (Blind ? something : "the fountain"));
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 */
1060 exercise(A_DEX, TRUE);
1063 if (IS_GRAVE(maploc->typ)) {
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));
1074 maploc->doormask = 0;
1075 (void) mksobj_at(ROCK, x, y, TRUE, FALSE);
1078 pline("Crack! %s broke!", Something);
1080 pline_The("headstone topples over and breaks!");
1085 if (maploc->typ == IRONBARS)
1087 if (IS_TREE(maploc->typ)) {
1088 struct obj *treefruit;
1089 /* nothing, fruit or trouble? 75:23.5:1.5% */
1091 if (!rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE))
1092 You_hear("a low buzzing."); /* a warning */
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));
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);
1114 exercise(A_DEX, TRUE);
1115 exercise(A_WIS, TRUE); /* discovered a new food source! */
1117 maploc->looted |= TREE_LOOTED;
1119 } else if (!(maploc->looted & TREE_SWARM)) {
1120 int cnt = rnl(4) + 2;
1126 if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE])
1127 && makemon(&mons[PM_KILLER_BEE], mm.x, mm.y,
1132 pline("You've attracted the tree's former occupants!");
1134 You("smell stale honey.");
1135 maploc->looted |= TREE_SWARM;
1140 if (IS_SINK(maploc->typ)) {
1141 int gend = poly_gender();
1142 short washerndx = (gend == 1 || (gend == 2 && rn2(2)))
1150 pline("Klunk! The pipes vibrate noisily.");
1153 exercise(A_DEX, TRUE);
1155 } else if (!(maploc->looted & S_LPUDDING) && !rn2(3)
1156 && !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) {
1158 You_hear("a gushing sound.");
1160 pline("A %s ooze gushes up from the drain!",
1162 (void) makemon(&mons[PM_BLACK_PUDDING], x, y, NO_MM_FLAGS);
1163 exercise(A_DEX, TRUE);
1165 maploc->looted |= S_LPUDDING;
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))
1173 maploc->looted |= S_LDWASHER;
1174 exercise(A_DEX, TRUE);
1176 } else if (!rn2(3)) {
1178 (Blind ? "You hear a sloshing sound"
1179 : "Muddy waste pops up from the drain"));
1180 if (!(maploc->looted & S_LRING)) { /* once per sink */
1182 You_see("a ring shining in its midst.");
1183 (void) mkobj_at(RING_CLASS, x, y, TRUE);
1185 exercise(A_DEX, TRUE);
1186 exercise(A_WIS, TRUE); /* a discovery! */
1187 maploc->looted |= S_LRING;
1193 if (maploc->typ == STAIRS || maploc->typ == LADDER
1194 || IS_STWALL(maploc->typ)) {
1195 if (!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN)
1198 pline("Ouch! That hurts!");
1199 exercise(A_DEX, FALSE);
1200 exercise(A_STR, FALSE);
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];
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 */
1222 if (maploc->doormask == D_ISOPEN || maploc->doormask == D_BROKEN
1223 || maploc->doormask == D_NODOOR) {
1225 exercise(A_DEX, FALSE);
1226 if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) {
1227 You("kick at empty space.");
1229 feel_location(x, y);
1231 pline("Dumb move! You strain a muscle.");
1232 exercise(A_STR, FALSE);
1233 set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
1235 if ((Is_airlevel(&u.uz) || Levitation) && rn2(2))
1236 hurtle(-u.dx, -u.dy, 1, TRUE);
1237 return 1; /* uses a turn */
1240 /* not enough leverage to kick open doors while levitating */
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) {
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;
1260 pline("As you kick the door, it crashes open!");
1261 exercise(A_STR, TRUE);
1262 maploc->doormask = D_BROKEN;
1264 feel_newsym(x, y); /* we know we broke it */
1265 unblock_point(x, y); /* vision */
1267 add_damage(x, y, 400L);
1268 pay_for_damage("break", FALSE);
1271 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1272 if (DEADMONSTER(mtmp))
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);
1283 feel_location(x, y); /* we know we hit it */
1284 exercise(A_STR, TRUE);
1287 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1288 if (DEADMONSTER(mtmp))
1290 if (is_watch(mtmp->data) && mtmp->mpeaceful
1291 && couldsee(mtmp->mx, mtmp->my)) {
1292 if (levl[x][y].looted & D_WARNED) {
1294 "Halt, vandal! You're under arrest!");
1295 (void) angry_guards(FALSE);
1297 mon_yells(mtmp, "Hey, stop damaging that door!");
1298 levl[x][y].looted |= D_WARNED;
1312 /* cover all the MIGR_xxx choices generated by down_gate() */
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;
1319 } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) {
1322 } /* else fall to the next cases */
1323 case MIGR_STAIRS_UP:
1324 case MIGR_LADDER_UP:
1326 cc->y = u.uz.dlevel + 1;
1329 cc->x = sstairs.tolev.dnum;
1330 cc->y = sstairs.tolev.dlevel;
1334 /* y==0 means "nowhere", in which case x doesn't matter */
1340 /* player or missile impacts location, causing objects to fall down */
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 */
1348 register struct obj *obj, *obj2;
1349 register struct monst *shkp;
1350 long oct, dct, price, debit, robbed;
1351 boolean angry, costly, isrock;
1357 toloc = down_gate(x, y);
1358 drop_to(&cc, toloc);
1363 /* send objects next to player falling through trap door.
1364 * checked in obj_delivery().
1366 toloc = MIGR_WITH_HERO;
1370 costly = costly_spot(x, y);
1371 price = debit = robbed = 0L;
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.
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;
1388 isrock = (missile && missile->otyp == ROCK);
1390 for (obj = level.objects[x][y]; obj; obj = obj2) {
1391 obj2 = obj->nexthere;
1394 /* number of objects in the pile */
1396 if (obj == uball || obj == uchain)
1398 /* boulders can fall too, but rarely & never due to rocks */
1399 if ((isrock && obj->otyp == BOULDER)
1400 || rn2(obj->otyp == BOULDER ? 30 : 3))
1402 obj_extract_self(obj);
1405 price += stolen_value(
1406 obj, x, y, (costly_spot(u.ux, u.uy)
1407 && index(u.urooms, *in_rooms(x, y, SHOPBASE))),
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)
1416 add_to_migration(obj);
1419 obj->owornmask = (long) toloc;
1421 /* number of fallen objects */
1425 if (dct && cansee(x, y)) { /* at least one object fell */
1426 const char *what = (dct == 1L ? "object falls" : "objects fall");
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,
1435 pline("%s adjacent %s %s.",
1436 dct == 1L ? "One of the" : "Some of the",
1437 dct == 1L ? "objects falls" : what, gate_str);
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);
1447 pline("%s is infuriated!", Monnam(shkp));
1449 pline("\"%s, you are a thief!\"", plname);
1451 You_hear("a scream, \"Thief!\"");
1453 (void) angry_guards(FALSE);
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,
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.
1469 ship_object(otmp, x, y, shop_floor_obj)
1472 boolean shop_floor_obj;
1479 boolean nodrop, unpaid, container, impact = FALSE;
1484 if ((toloc = down_gate(x, y)) == MIGR_NOWHERE)
1486 drop_to(&cc, toloc);
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));
1495 container = Has_contents(otmp);
1496 unpaid = is_unpaid(otmp);
1499 for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
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)) {
1510 impact_drop(otmp, x, y, 0);
1511 return FALSE; /* let caller finish the drop */
1515 otransit_msg(otmp, nodrop, n);
1519 impact_drop(otmp, x, y, 0);
1523 if (unpaid || shop_floor_obj) {
1525 (void) stolen_value(otmp, u.ux, u.uy, TRUE, FALSE);
1529 (void) stolen_value(
1531 (costly_spot(u.ux, u.uy)
1532 && index(u.urooms, *in_rooms(ox, oy, SHOPBASE))),
1535 /* set otmp->no_charge to 0 */
1537 picked_container(otmp); /* happens to do the right thing */
1538 if (otmp->oclass != COIN_CLASS)
1539 otmp->no_charge = 0;
1542 if (otmp->owornmask)
1543 remove_worn_item(otmp, TRUE);
1545 /* some things break rather than ship */
1546 if (breaktest(otmp)) {
1549 if (objects[otmp->otyp].oc_material == GLASS
1550 || otmp->otyp == EXPENSIVE_CAMERA) {
1551 if (otmp->otyp == MIRROR)
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));
1560 You_hear("a muffled %s.", result);
1561 obj_extract_self(otmp);
1562 obfree(otmp, (struct obj *) 0);
1566 add_to_migration(otmp);
1569 otmp->owornmask = (long) toloc;
1570 /* boulder from rolling boulder trap, no longer part of the trap */
1571 if (otmp->otyp == BOULDER)
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.
1584 impact_drop(otmp, x, y, 0);
1591 obj_delivery(near_hero)
1594 register struct obj *otmp, *otmp2;
1595 register int nx, ny;
1597 boolean nobreak, noscatter;
1599 for (otmp = migrating_objs; otmp; otmp = otmp2) {
1601 if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel)
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);
1609 if (!near_hero ^ (where == MIGR_WITH_HERO))
1612 obj_extract_self(otmp);
1613 otmp->owornmask = 0L;
1616 case MIGR_STAIRS_UP:
1617 nx = xupstair, ny = yupstair;
1619 case MIGR_LADDER_UP:
1620 nx = xupladder, ny = yupladder;
1623 nx = sstairs.sx, ny = sstairs.sy;
1625 case MIGR_WITH_HERO:
1626 nx = u.ux, ny = u.uy;
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))
1639 } else if (breaktest(otmp)) {
1640 /* assume it broke before player arrived, no messages */
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 */
1661 otransit_msg(otmp, nodrop, num)
1662 register struct obj *otmp;
1663 register boolean nodrop;
1668 Sprintf(obuf, "%s%s",
1669 (otmp->otyp == CORPSE && type_is_pname(&mons[otmp->corpsenm]))
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" : "");
1678 Sprintf(eos(obuf), ".");
1680 Sprintf(eos(obuf), " and %s %s.", otense(otmp, "fall"), gate_str);
1683 pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str);
1686 /* migration destination for objects which fall down to next level */
1694 /* this matches the player restriction in goto_level() */
1695 if (on_level(&u.uz, &qstart_level) && !ok_to_quest())
1696 return MIGR_NOWHERE;
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
1704 if (xdnladder == x && ydnladder == y) {
1705 gate_str = "down the ladder";
1706 return MIGR_LADDER_UP;
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";
1715 return MIGR_NOWHERE;