1 /* SCCS Id: @(#)dokick.c 3.4 2003/12/04 */
2 /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
3 /* NetHack may be freely redistributed. See license for details. */
8 #define is_bigfoot(x) ((x) == &mons[PM_SASQUATCH])
9 #define martial() (martial_bonus() || is_bigfoot(youmonst.data) || \
10 (uarmf && uarmf->otyp == KICKING_BOOTS))
12 static NEARDATA struct rm *maploc;
13 static NEARDATA const char *gate_str;
15 extern boolean notonhead; /* for long worms */
17 STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P));
18 STATIC_DCL void FDECL(kick_monster, (XCHAR_P, XCHAR_P));
19 STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P));
20 STATIC_DCL char *FDECL(kickstr, (char *));
21 STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long));
22 STATIC_DCL void FDECL(drop_to, (coord *,SCHAR_P));
24 static NEARDATA struct obj *kickobj;
26 static const char kick_passes_thru[] = "kick passes harmlessly through";
30 register struct monst *mon;
31 register boolean clumsy;
33 register int mdx, mdy;
34 register int dmg = ( ACURRSTR + ACURR(A_DEX) + ACURR(A_CON) )/ 15;
35 int kick_skill = P_NONE;
36 int blessed_foot_damage = 0;
37 boolean trapkilled = FALSE;
39 if (uarmf && uarmf->otyp == KICKING_BOOTS)
42 /* excessive wt affects dex, so it affects dmg */
45 /* kicking a dragon or an elephant will not harm it */
46 if (thick_skinned(mon->data)) dmg = 0;
48 /* attacking a shade is useless */
49 if (mon->data == &mons[PM_SHADE])
52 if ((is_undead(mon->data) || is_demon(mon->data)) && uarmf &&
54 blessed_foot_damage = 1;
56 if (mon->data == &mons[PM_SHADE] && !blessed_foot_damage) {
57 pline_The("%s.", kick_passes_thru);
58 /* doesn't exercise skill or abuse alignment or frighten pet,
59 and shades have no passive counterattack */
63 if(mon->m_ap_type) seemimic(mon);
67 /* squeeze some guilt feelings... */
71 monflee(mon, (dmg ? rnd(dmg) : 1), FALSE, FALSE);
77 /* convert potential damage to actual damage */
80 if (dmg > 1) kick_skill = P_MARTIAL_ARTS;
81 dmg += rn2(ACURR(A_DEX)/2 + 1);
83 /* a good kick exercises your dex */
84 exercise(A_DEX, TRUE);
86 if (blessed_foot_damage) dmg += rnd(4);
87 if (uarmf) dmg += uarmf->spe;
88 dmg += u.udaminc; /* add ring(s) of increase damage */
91 if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3) &&
92 mon->mcanmove && mon != u.ustuck && !mon->mtrapped) {
93 /* see if the monster has a place to move into */
96 if(goodpos(mdx, mdy, mon, 0)) {
97 pline("%s reels from the blow.", Monnam(mon));
98 if (m_in_out_region(mon, mdx, mdy)) {
99 remove_monster(mon->mx, mon->my);
100 newsym(mon->mx, mon->my);
101 place_monster(mon, mdx, mdy);
102 newsym(mon->mx, mon->my);
104 if (mintrap(mon) == 2) trapkilled = TRUE;
109 (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK);
110 if (mon->mhp <= 0 && !trapkilled) killed(mon);
112 /* may bring up a dialog, so put this after all messages */
113 if (kick_skill != P_NONE) /* exercise proficiency */
114 use_skill(kick_skill, 1);
121 register boolean clumsy = FALSE;
122 register struct monst *mon = m_at(x, y);
127 if (attack_checks(mon, (struct obj *)0)) return;
130 /* Kick attacks by kicking monsters are normal attacks, not special.
131 * This is almost always worthless, since you can either take one turn
132 * and do all your kicks, or else take one turn and attack the monster
133 * normally, getting all your attacks _including_ all your kicks.
134 * If you have >1 kick attack, you get all of them.
136 if (Upolyd && attacktype(youmonst.data, AT_KICK)) {
137 struct attack *uattk;
139 schar tmp = find_roll_to_hit(mon);
141 for (i = 0; i < NATTK; i++) {
142 /* first of two kicks might have provoked counterattack
143 that has incapacitated the hero (ie, floating eye) */
144 if (multi < 0) break;
146 uattk = &youmonst.data->mattk[i];
147 /* we only care about kicking attacks here */
148 if (uattk->aatyp != AT_KICK) continue;
150 if (mon->data == &mons[PM_SHADE] &&
151 (!uarmf || !uarmf->blessed)) {
152 /* doesn't matter whether it would have hit or missed,
153 and shades have no passive counterattack */
154 Your("%s %s.", kick_passes_thru, mon_nam(mon));
155 break; /* skip any additional kicks */
156 } else if (tmp > rnd(20)) {
157 You("kick %s.", mon_nam(mon));
158 sum = damageum(mon, uattk);
159 (void)passive(mon, (boolean)(sum > 0), (sum != 2), AT_KICK);
161 break; /* Defender died */
164 (void)passive(mon, 0, 1, AT_KICK);
170 if(Levitation && !rn2(3) && verysmall(mon->data) &&
171 !is_flyer(mon->data)) {
172 pline("Floating in the air, you miss wildly!");
173 exercise(A_DEX, FALSE);
174 (void) passive(mon, FALSE, 1, AT_KICK);
182 if(!rn2((i < j/10) ? 2 : (i < j/5) ? 3 : 4)) {
183 if(martial() && !rn2(2)) goto doit;
184 Your("clumsy kick does no damage.");
185 (void) passive(mon, FALSE, 1, AT_KICK);
188 if(i < j/10) clumsy = TRUE;
189 else if(!rn2((i < j/5) ? 2 : 3)) clumsy = TRUE;
192 if(Fumbling) clumsy = TRUE;
194 else if(uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
197 You("kick %s.", mon_nam(mon));
198 if(!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data)) &&
199 mon->mcansee && !mon->mtrapped && !thick_skinned(mon->data) &&
200 mon->data->mlet != S_EEL && haseyes(mon->data) && mon->mcanmove &&
201 !mon->mstun && !mon->mconf && !mon->msleeping &&
202 mon->data->mmove >= 12) {
203 if(!nohands(mon->data) && !rn2(martial() ? 5 : 3)) {
204 pline("%s blocks your %skick.", Monnam(mon),
205 clumsy ? "clumsy " : "");
206 (void) passive(mon, FALSE, 1, AT_KICK);
210 if(mon->mx != x || mon->my != y) {
211 if(glyph_is_invisible(levl[x][y].glyph)) {
215 pline("%s %s, %s evading your %skick.", Monnam(mon),
216 (can_teleport(mon->data) ? "teleports" :
217 is_floater(mon->data) ? "floats" :
218 is_flyer(mon->data) ? "swoops" :
219 (nolimbs(mon->data) || slithy(mon->data)) ?
221 clumsy ? "easily" : "nimbly",
222 clumsy ? "clumsy " : "");
223 (void) passive(mon, FALSE, 1, AT_KICK);
228 kickdmg(mon, clumsy);
232 * Return TRUE if caught (the gold taken care of), FALSE otherwise.
233 * The gold object is *not* attached to the fobj chain!
237 register struct monst *mtmp;
238 register struct obj *gold;
240 boolean msg_given = FALSE;
242 if(!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest
243 && !is_mercenary(mtmp->data)) {
245 } else if (!mtmp->mcanmove) {
246 /* too light to do real damage */
247 if (canseemon(mtmp)) {
248 pline_The("%s harmlessly %s %s.", xname(gold),
249 otense(gold, "hit"), mon_nam(mtmp));
254 long value = gold->quan * objects[gold->otyp].oc_cost;
258 if(!rn2(4)) setmangry(mtmp); /* not always pleasing */
260 /* greedy monsters catch gold */
261 if (cansee(mtmp->mx, mtmp->my))
262 pline("%s catches the gold.", Monnam(mtmp));
264 mtmp->mgold += gold->quan;
267 long robbed = ESHK(mtmp)->robbed;
271 robbed -= gold->quan;
275 if (robbed < 0) robbed = 0;
276 pline_The("amount %scovers %s recent losses.",
277 !robbed ? "" : "partially ",
279 ESHK(mtmp)->robbed = robbed;
281 make_happy_shk(mtmp, FALSE);
283 if(mtmp->mpeaceful) {
285 ESHK(mtmp)->credit += gold->quan;
287 ESHK(mtmp)->credit += value;
289 You("have %ld %s in credit.",
291 currency(ESHK(mtmp)->credit));
292 } else verbalize("Thanks, scum!");
294 } else if (mtmp->ispriest) {
296 verbalize("Thank you for your contribution.");
297 else verbalize("Thanks, scum!");
298 } else if (is_mercenary(mtmp->data)) {
302 if (mtmp->data == &mons[PM_SOLDIER])
304 else if (mtmp->data == &mons[PM_SERGEANT])
306 else if (mtmp->data == &mons[PM_LIEUTENANT])
308 else if (mtmp->data == &mons[PM_CAPTAIN])
313 if (gold->quan > goldreqd +
314 (u.ugold + u.ulevel*rn2(5))/ACURR(A_CHA))
316 if (value > goldreqd +
317 (money_cnt(invent) + u.ulevel*rn2(5))/ACURR(A_CHA))
319 mtmp->mpeaceful = TRUE;
323 verbalize("That should do. Now beat it!");
324 else verbalize("That's not enough, coward!");
330 add_to_minv(mtmp, gold);
335 if (!msg_given) miss(xname(gold), mtmp);
339 /* container is kicked, dropped, thrown or otherwise impacted by player.
340 * Assumes container is on floor. Checks contents for possible damage. */
342 container_impact_dmg(obj)
346 struct obj *otmp, *otmp2;
348 boolean costly, insider;
349 xchar x = obj->ox, y = obj->oy;
351 /* only consider normal containers */
352 if (!Is_container(obj) || Is_mbag(obj)) return;
354 costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) &&
356 insider = (*u.ushops && inside_shop(u.ux, u.uy) &&
357 *in_rooms(x, y, SHOPBASE) == *u.ushops);
359 for (otmp = obj->cobj; otmp; otmp = otmp2) {
360 const char *result = (char *)0;
363 if (objects[otmp->otyp].oc_material == GLASS &&
364 otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) {
366 } else if (otmp->otyp == EGG && !rn2(3)) {
370 if (otmp->otyp == MIRROR) change_luck(-2);
372 /* eggs laid by you. penalty is -1 per egg, max 5,
373 * but it's always exactly 1 that breaks */
374 if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
376 You_hear("a muffled %s.", result);
378 loss += stolen_value(otmp, x, y,
379 (boolean)shkp->mpeaceful, TRUE);
383 obj_extract_self(otmp);
384 obfree(otmp, (struct obj *) 0);
388 if (costly && loss) {
390 You("caused %ld %s worth of damage!", loss, currency(loss));
391 make_angry_shk(shkp, x, y);
393 You("owe %s %ld %s for objects destroyed.",
394 mon_nam(shkp), loss, currency(loss));
404 register struct monst *mon, *shkp;
407 boolean costly, isgold, slide = FALSE;
409 /* if a pile, the "top" object gets kicked */
410 kickobj = level.objects[x][y];
412 /* kickobj should always be set due to conditions of call */
413 if(!kickobj || kickobj->otyp == BOULDER
414 || kickobj == uball || kickobj == uchain)
417 if ((trap = t_at(x,y)) != 0 &&
418 (((trap->ttyp == PIT ||
419 trap->ttyp == SPIKED_PIT) && !Passes_walls) ||
420 trap->ttyp == WEB)) {
421 if (!trap->tseen) find_trap(trap);
422 You_cant("kick %s that's in a %s!", something,
423 Hallucination ? "tizzy" :
424 (trap->ttyp == WEB) ? "web" : "pit");
428 if(Fumbling && !rn2(3)) {
429 Your("clumsy kick missed.");
433 if(kickobj->otyp == CORPSE && touch_petrifies(&mons[kickobj->corpsenm])
434 && !Stone_resistance && !uarmf) {
437 You("kick the %s with your bare %s.",
438 corpse_xname(kickobj, TRUE), makeplural(body_part(FOOT)));
439 if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) {
440 You("turn to stone...");
441 killer_format = KILLED_BY;
442 /* KMH -- otmp should be kickobj */
443 Sprintf(kbuf, "kicking %s without boots",
444 an(corpse_xname(kickobj, TRUE)));
450 /* range < 2 means the object will not move. */
451 /* maybe dexterity should also figure here. */
452 range = (int)((ACURRSTR)/2 - kickobj->owt/40);
454 if(martial()) range += rnd(3);
457 /* you're in the water too; significantly reduce range */
458 range = range / 3 + 1; /* {1,2}=>1, {3,4,5}=>2, {6,7,8}=>3 */
460 if (is_ice(x, y)) range += rnd(3), slide = TRUE;
461 if (kickobj->greased) range += rnd(3), slide = TRUE;
464 /* Mjollnir is magically too heavy to kick */
465 if(kickobj->oartifact == ART_MJOLLNIR) range = 1;
467 /* see if the object has a place to move into */
468 if(!ZAP_POS(levl[x+u.dx][y+u.dy].typ) || closed_door(x+u.dx, y+u.dy))
471 costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) &&
473 isgold = (kickobj->oclass == COIN_CLASS);
475 if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
476 if ((!martial() && rn2(20) > ACURR(A_DEX)) ||
477 IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) {
479 pline("It doesn't come loose.");
481 pline("%s %sn't come loose.",
482 The(distant_name(kickobj, xname)),
483 otense(kickobj, "do"));
484 return (!rn2(3) || martial());
487 pline("It comes loose.");
489 pline("%s %s loose.",
490 The(distant_name(kickobj, xname)),
491 otense(kickobj, "come"));
492 obj_extract_self(kickobj);
494 if (costly && (!costly_spot(u.ux, u.uy) ||
495 !index(u.urooms, *in_rooms(x, y, SHOPBASE))))
496 addtobill(kickobj, FALSE, FALSE, FALSE);
497 if (!flooreffects(kickobj, u.ux, u.uy, "fall")) {
498 place_object(kickobj, u.ux, u.uy);
505 /* a box gets a chance of breaking open here */
506 if(Is_box(kickobj)) {
507 boolean otrp = kickobj->otrapped;
509 if(range < 2) pline("THUD!");
511 container_impact_dmg(kickobj);
513 if (kickobj->olocked) {
514 if (!rn2(5) || (martial() && !rn2(2))) {
515 You("break open the lock!");
516 kickobj->olocked = 0;
517 kickobj->obroken = 1;
518 if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
522 if (!rn2(3) || (martial() && !rn2(2))) {
523 pline_The("lid slams open, then falls shut.");
524 if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
528 if(range < 2) return(1);
529 /* else let it fall through to the next cases... */
532 /* fragile objects should not be kicked */
533 if (hero_breaks(kickobj, kickobj->ox, kickobj->oy, FALSE)) return 1;
535 /* too heavy to move. range is calculated as potential distance from
536 * player, so range == 2 means the object may move up to one square
537 * from its current position
539 if(range < 2 || (isgold && kickobj->quan > 300L)) {
540 if(!Is_box(kickobj)) pline("Thump!");
541 return(!rn2(3) || martial());
544 if (kickobj->quan > 1L && !isgold) kickobj = splitobj(kickobj, 1L);
547 pline("Whee! %s %s across the %s.", Doname2(kickobj),
548 otense(kickobj, "slide"), surface(x,y));
550 obj_extract_self(kickobj);
551 (void) snuff_candle(kickobj);
553 mon = bhit(u.dx, u.dy, range, KICKED_WEAPON,
554 (int FDECL((*),(MONST_P,OBJ_P)))0,
555 (int FDECL((*),(OBJ_P,OBJ_P)))0,
560 kickobj->where == OBJ_MINVENT && kickobj->ocarry == mon)
561 return 1; /* alert shk caught it */
562 notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
563 if (isgold ? ghitm(mon, kickobj) : /* caught? */
564 thitmonst(mon, kickobj)) /* hit && used up? */
568 /* the object might have fallen down a hole */
569 if (kickobj->where == OBJ_MIGRATING) {
572 costly_gold(x, y, kickobj->quan);
573 else (void)stolen_value(kickobj, x, y,
574 (boolean)shkp->mpeaceful, FALSE);
579 bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE);
580 if (costly && (!costly_spot(bhitpos.x, bhitpos.y) ||
581 *in_rooms(x, y, SHOPBASE) != bhitroom)) {
583 costly_gold(x, y, kickobj->quan);
584 else (void)stolen_value(kickobj, x, y,
585 (boolean)shkp->mpeaceful, FALSE);
588 if(flooreffects(kickobj,bhitpos.x,bhitpos.y,"fall")) return(1);
589 place_object(kickobj, bhitpos.x, bhitpos.y);
591 newsym(kickobj->ox, kickobj->oy);
601 if (kickobj) what = distant_name(kickobj,doname);
602 else if (IS_DOOR(maploc->typ)) what = "a door";
603 else if (IS_TREE(maploc->typ)) what = "a tree";
604 else if (IS_STWALL(maploc->typ)) what = "a wall";
605 else if (IS_ROCK(maploc->typ)) what = "a rock";
606 else if (IS_THRONE(maploc->typ)) what = "a throne";
607 else if (IS_FOUNTAIN(maploc->typ)) what = "a fountain";
608 else if (IS_GRAVE(maploc->typ)) what = "a headstone";
610 else if (IS_SINK(maploc->typ)) what = "a sink";
612 else if (IS_ALTAR(maploc->typ)) what = "an altar";
613 else if (IS_DRAWBRIDGE(maploc->typ)) what = "a drawbridge";
614 else if (maploc->typ == STAIRS) what = "the stairs";
615 else if (maploc->typ == LADDER) what = "a ladder";
616 else if (maploc->typ == IRONBARS) what = "an iron bar";
617 else what = "something weird";
618 return strcat(strcpy(buf, "kicking "), what);
626 register struct monst *mtmp;
627 boolean no_kick = FALSE;
630 if (nolimbs(youmonst.data) || slithy(youmonst.data)) {
631 You("have no legs to kick with.");
633 } else if (verysmall(youmonst.data)) {
634 You("are too small to do any kicking.");
637 } else if (u.usteed) {
638 if (yn_function("Kick your steed?", ynchars, 'y') == 'y') {
639 You("kick %s.", mon_nam(u.usteed));
646 } else if (Wounded_legs) {
647 /* note: jump() has similar code */
648 long wl = (EWounded_legs & BOTH_SIDES);
649 const char *bp = body_part(LEG);
651 if (wl == BOTH_SIDES) bp = makeplural(bp);
652 Your("%s%s %s in no shape for kicking.",
653 (wl == LEFT_SIDE) ? "left " :
654 (wl == RIGHT_SIDE) ? "right " : "",
655 bp, (wl == BOTH_SIDES) ? "are" : "is");
657 } else if (near_capacity() > SLT_ENCUMBER) {
658 Your("load is too heavy to balance yourself for a kick.");
660 } else if (youmonst.data->mlet == S_LIZARD) {
661 Your("legs cannot kick effectively.");
663 } else if (u.uinwater && !rn2(2)) {
664 Your("slow motion kick doesn't hit anything.");
666 } else if (u.utrap) {
667 switch (u.utraptype) {
669 pline("There's not enough room to kick down here.");
673 You_cant("move your %s!", body_part(LEG));
682 /* ignore direction typed before player notices kick failed */
683 display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
687 if(!getdir((char *)0)) return(0);
688 if(!u.dx && !u.dy) return(0);
693 /* KMH -- Kicking boots always succeed */
694 if (uarmf && uarmf->otyp == KICKING_BOOTS)
697 avrg_attrib = (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3;
701 case 0: You_cant("move your %s!", body_part(LEG));
703 case 1: if (is_animal(u.ustuck->data)) {
704 pline("%s burps loudly.", Monnam(u.ustuck));
707 default: Your("feeble kick has no effect."); break;
716 /* doors can be opened while levitating, so they must be
717 * reachable for bracing purposes
718 * Possible extension: allow bracing against stuff on the side?
720 if (isok(xx,yy) && !IS_ROCK(levl[xx][yy].typ) &&
721 !IS_DOOR(levl[xx][yy].typ) &&
722 (!Is_airlevel(&u.uz) || !OBJ_AT(xx,yy))) {
723 You("have nothing to brace yourself against.");
731 maploc = &levl[x][y];
733 /* The next five tests should stay in */
734 /* their present order: monsters, pools, */
735 /* objects, non-doors, doors. */
738 struct permonst *mdat;
742 if (!mtmp->mpeaceful || !canspotmon(mtmp))
743 flags.forcefight = TRUE; /* attack even if invisible */
745 flags.forcefight = FALSE;
746 /* see comment in attack_checks() */
747 if (!DEADMONSTER(mtmp) &&
749 /* check x and y; a monster that evades your kick by
750 jumping to an unseen square doesn't leave an I behind */
751 mtmp->mx == x && mtmp->my == y &&
752 !glyph_is_invisible(levl[x][y].glyph) &&
753 !(u.uswallow && mtmp == u.ustuck))
755 if((Is_airlevel(&u.uz) || Levitation) && flags.move) {
758 range = ((int)youmonst.data->cwt + (weight_cap() + inv_weight()));
759 if (range < 1) range = 1; /* divide by zero avoidance */
760 range = (3*(int)mdat->cwt) / range;
762 if(range < 1) range = 1;
763 hurtle(-u.dx, -u.dy, range, TRUE);
767 if (glyph_is_invisible(levl[x][y].glyph)) {
771 if (is_pool(x, y) ^ !!u.uinwater) {
772 /* objects normally can't be removed from water by kicking */
773 You("splash some water around.");
777 kickobj = (struct obj *)0;
779 (!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
780 || sobj_at(BOULDER,x,y))) {
781 if(kick_object(x, y)) {
782 if(Is_airlevel(&u.uz))
783 hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */
789 if(!IS_DOOR(maploc->typ)) {
790 if(maploc->typ == SDOOR) {
791 if(!Levitation && rn2(30) < avrg_attrib) {
792 cvt_sdoor_to_door(maploc); /* ->typ = DOOR */
793 pline("Crash! %s a secret door!",
794 /* don't "kick open" when it's locked
795 unless it also happens to be trapped */
796 (maploc->doormask & (D_LOCKED|D_TRAPPED)) == D_LOCKED ?
797 "Your kick uncovers" : "You kick open");
798 exercise(A_DEX, TRUE);
799 if(maploc->doormask & D_TRAPPED) {
800 maploc->doormask = D_NODOOR;
801 b_trapped("door", FOOT);
802 } else if (maploc->doormask != D_NODOOR &&
803 !(maploc->doormask & D_LOCKED))
804 maploc->doormask = D_ISOPEN;
806 feel_location(x,y); /* we know it's gone */
809 if (maploc->doormask == D_ISOPEN ||
810 maploc->doormask == D_NODOOR)
811 unblock_point(x,y); /* vision */
815 if(maploc->typ == SCORR) {
816 if(!Levitation && rn2(30) < avrg_attrib) {
817 pline("Crash! You kick open a secret passage!");
818 exercise(A_DEX, TRUE);
821 feel_location(x,y); /* we know it's gone */
824 unblock_point(x,y); /* vision */
828 if(IS_THRONE(maploc->typ)) {
830 if(Levitation) goto dumb;
831 if((Luck < 0 || maploc->doormask) && !rn2(3)) {
833 maploc->doormask = 0; /* don't leave loose ends.. */
834 (void) mkgold((long)rnd(200), x, y);
836 pline("CRASH! You destroy it.");
838 pline("CRASH! You destroy the throne.");
841 exercise(A_DEX, TRUE);
843 } else if(Luck > 0 && !rn2(3) && !maploc->looted) {
844 (void) mkgold((long) rn1(201, 300), x, y);
848 (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL,
849 LUCKSTONE-1), x, y, FALSE, TRUE);
851 You("kick %s loose!", something);
853 You("kick loose some ornamental coins and gems!");
856 /* prevent endless milking */
857 maploc->looted = T_LOOTED;
859 } else if (!rn2(4)) {
860 if(dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) {
867 if(IS_ALTAR(maploc->typ)) {
868 if(Levitation) goto dumb;
869 You("kick %s.",(Blind ? something : "the altar"));
870 if(!rn2(3)) goto ouch;
872 exercise(A_DEX, TRUE);
875 if(IS_FOUNTAIN(maploc->typ)) {
876 if(Levitation) goto dumb;
877 You("kick %s.",(Blind ? something : "the fountain"));
878 if(!rn2(3)) goto ouch;
879 /* make metal boots rust */
881 if (!rust_dmg(uarmf, "metal boots", 1, FALSE, &youmonst)) {
882 Your("boots get wet.");
883 /* could cause short-lived fumbling here */
885 exercise(A_DEX, TRUE);
888 if(IS_GRAVE(maploc->typ) || maploc->typ == IRONBARS)
890 if(IS_TREE(maploc->typ)) {
891 struct obj *treefruit;
892 /* nothing, fruit or trouble? 75:23.5:1.5% */
894 if ( !rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE) )
895 You_hear("a low buzzing."); /* a warning */
898 if (rn2(15) && !(maploc->looted & TREE_LOOTED) &&
899 (treefruit = rnd_treefruit_at(x, y))) {
900 long nfruit = 8L-rnl(7), nfall;
901 short frtype = treefruit->otyp;
902 treefruit->quan = nfruit;
903 if (is_plural(treefruit))
904 pline("Some %s fall from the tree!", xname(treefruit));
906 pline("%s falls from the tree!", An(xname(treefruit)));
907 nfall = scatter(x,y,2,MAY_HIT,treefruit);
908 if (nfall != nfruit) {
909 /* scatter left some in the tree, but treefruit
910 * may not refer to the correct object */
911 treefruit = mksobj(frtype, TRUE, FALSE);
912 treefruit->quan = nfruit-nfall;
913 pline("%ld %s got caught in the branches.",
914 nfruit-nfall, xname(treefruit));
915 dealloc_obj(treefruit);
917 exercise(A_DEX, TRUE);
918 exercise(A_WIS, TRUE); /* discovered a new food source! */
920 maploc->looted |= TREE_LOOTED;
922 } else if (!(maploc->looted & TREE_SWARM)) {
923 int cnt = rnl(4) + 2;
928 if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE])
929 && makemon(&mons[PM_KILLER_BEE],
930 mm.x, mm.y, MM_ANGRY))
934 pline("You've attracted the tree's former occupants!");
936 You("smell stale honey.");
937 maploc->looted |= TREE_SWARM;
943 if(IS_SINK(maploc->typ)) {
944 int gend = poly_gender();
945 short washerndx = (gend == 1 || (gend == 2 && rn2(2))) ?
946 PM_INCUBUS : PM_SUCCUBUS;
948 if(Levitation) goto dumb;
951 pline("Klunk! The pipes vibrate noisily.");
952 else pline("Klunk!");
953 exercise(A_DEX, TRUE);
955 } else if(!(maploc->looted & S_LPUDDING) && !rn2(3) &&
956 !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) {
958 You_hear("a gushing sound.");
960 pline("A %s ooze gushes up from the drain!",
962 (void) makemon(&mons[PM_BLACK_PUDDING],
964 exercise(A_DEX, TRUE);
966 maploc->looted |= S_LPUDDING;
968 } else if(!(maploc->looted & S_LDWASHER) && !rn2(3) &&
969 !(mvitals[washerndx].mvflags & G_GONE)) {
970 /* can't resist... */
971 pline("%s returns!", (Blind ? Something :
973 if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS))
975 maploc->looted |= S_LDWASHER;
976 exercise(A_DEX, TRUE);
979 pline("Flupp! %s.", (Blind ?
980 "You hear a sloshing sound" :
981 "Muddy waste pops up from the drain"));
982 if(!(maploc->looted & S_LRING)) { /* once per sink */
984 You("see a ring shining in its midst.");
985 (void) mkobj_at(RING_CLASS, x, y, TRUE);
987 exercise(A_DEX, TRUE);
988 exercise(A_WIS, TRUE); /* a discovery! */
989 maploc->looted |= S_LRING;
996 if (maploc->typ == STAIRS || maploc->typ == LADDER ||
997 IS_STWALL(maploc->typ)) {
998 if(!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN)
1001 pline("Ouch! That hurts!");
1002 exercise(A_DEX, FALSE);
1003 exercise(A_STR, FALSE);
1004 if (Blind) feel_location(x,y); /* we know we hit it */
1005 if (is_drawbridge_wall(x,y) >= 0) {
1006 pline_The("drawbridge is unaffected.");
1007 /* update maploc to refer to the drawbridge */
1008 (void) find_drawbridge(&x,&y);
1009 maploc = &levl[x][y];
1011 if(!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
1012 losehp(rnd(ACURR(A_CON) > 15 ? 3 : 5), kickstr(buf),
1014 if(Is_airlevel(&u.uz) || Levitation)
1015 hurtle(-u.dx, -u.dy, rn1(2,4), TRUE); /* assume it's heavy */
1021 if(maploc->doormask == D_ISOPEN ||
1022 maploc->doormask == D_BROKEN ||
1023 maploc->doormask == D_NODOOR) {
1025 exercise(A_DEX, FALSE);
1026 if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) {
1027 You("kick at empty space.");
1028 if (Blind) feel_location(x,y);
1030 pline("Dumb move! You strain a muscle.");
1031 exercise(A_STR, FALSE);
1032 set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
1034 if ((Is_airlevel(&u.uz) || Levitation) && rn2(2)) {
1035 hurtle(-u.dx, -u.dy, 1, TRUE);
1036 return 1; /* you moved, so use up a turn */
1041 /* not enough leverage to kick open doors while levitating */
1042 if(Levitation) goto ouch;
1044 exercise(A_DEX, TRUE);
1045 /* door is known to be CLOSED or LOCKED */
1046 if(rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
1047 boolean shopdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE;
1048 /* break the door */
1049 if(maploc->doormask & D_TRAPPED) {
1050 if (flags.verbose) You("kick the door.");
1051 exercise(A_STR, FALSE);
1052 maploc->doormask = D_NODOOR;
1053 b_trapped("door", FOOT);
1054 } else if(ACURR(A_STR) > 18 && !rn2(5) && !shopdoor) {
1055 pline("As you kick the door, it shatters to pieces!");
1056 exercise(A_STR, TRUE);
1057 maploc->doormask = D_NODOOR;
1059 pline("As you kick the door, it crashes open!");
1060 exercise(A_STR, TRUE);
1061 maploc->doormask = D_BROKEN;
1064 feel_location(x,y); /* we know we broke it */
1067 unblock_point(x,y); /* vision */
1069 add_damage(x, y, 400L);
1070 pay_for_damage("break", FALSE);
1073 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1074 if (DEADMONSTER(mtmp)) continue;
1075 if((mtmp->data == &mons[PM_WATCHMAN] ||
1076 mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
1077 couldsee(mtmp->mx, mtmp->my) &&
1079 if (canspotmon(mtmp))
1080 pline("%s yells:", Amonnam(mtmp));
1082 You_hear("someone yell:");
1083 verbalize("Halt, thief! You're under arrest!");
1084 (void) angry_guards(FALSE);
1089 if (Blind) feel_location(x,y); /* we know we hit it */
1090 exercise(A_STR, TRUE);
1093 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1094 if (DEADMONSTER(mtmp)) continue;
1095 if ((mtmp->data == &mons[PM_WATCHMAN] ||
1096 mtmp->data == &mons[PM_WATCH_CAPTAIN]) &&
1097 mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my)) {
1098 if (canspotmon(mtmp))
1099 pline("%s yells:", Amonnam(mtmp));
1101 You_hear("someone yell:");
1102 if(levl[x][y].looted & D_WARNED) {
1103 verbalize("Halt, vandal! You're under arrest!");
1104 (void) angry_guards(FALSE);
1106 verbalize("Hey, stop damaging that door!");
1107 levl[x][y].looted |= D_WARNED;
1121 /* cover all the MIGR_xxx choices generated by down_gate() */
1123 case MIGR_RANDOM: /* trap door or hole */
1124 if (Is_stronghold(&u.uz)) {
1125 cc->x = valley_level.dnum;
1126 cc->y = valley_level.dlevel;
1128 } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) {
1131 } /* else fall to the next cases */
1132 case MIGR_STAIRS_UP:
1133 case MIGR_LADDER_UP:
1135 cc->y = u.uz.dlevel + 1;
1138 cc->x = sstairs.tolev.dnum;
1139 cc->y = sstairs.tolev.dlevel;
1143 /* y==0 means "nowhere", in which case x doesn't matter */
1150 impact_drop(missile, x, y, dlev)
1151 struct obj *missile;
1155 register struct obj *obj, *obj2;
1156 register struct monst *shkp;
1157 long oct, dct, price, debit, robbed;
1158 boolean angry, costly, isrock;
1161 if(!OBJ_AT(x, y)) return;
1163 toloc = down_gate(x, y);
1164 drop_to(&cc, toloc);
1168 /* send objects next to player falling through trap door.
1169 * checked in obj_delivery().
1171 toloc = MIGR_NEAR_PLAYER;
1175 costly = costly_spot(x, y);
1176 price = debit = robbed = 0L;
1178 shkp = (struct monst *) 0;
1179 /* if 'costly', we must keep a record of ESHK(shkp) before
1180 * it undergoes changes through the calls to stolen_value.
1181 * the angry bit must be reset, if needed, in this fn, since
1182 * stolen_value is called under the 'silent' flag to avoid
1183 * unsavory pline repetitions.
1186 if ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0) {
1187 debit = ESHK(shkp)->debit;
1188 robbed = ESHK(shkp)->robbed;
1189 angry = !shkp->mpeaceful;
1193 isrock = (missile && missile->otyp == ROCK);
1195 for(obj = level.objects[x][y]; obj; obj = obj2) {
1196 obj2 = obj->nexthere;
1197 if(obj == missile) continue;
1198 /* number of objects in the pile */
1200 if(obj == uball || obj == uchain) continue;
1201 /* boulders can fall too, but rarely & never due to rocks */
1202 if((isrock && obj->otyp == BOULDER) ||
1203 rn2(obj->otyp == BOULDER ? 30 : 3)) continue;
1204 obj_extract_self(obj);
1207 price += stolen_value(obj, x, y,
1208 (costly_spot(u.ux, u.uy) &&
1209 index(u.urooms, *in_rooms(x, y, SHOPBASE))),
1211 /* set obj->no_charge to 0 */
1212 if (Has_contents(obj))
1213 picked_container(obj); /* does the right thing */
1214 if (obj->oclass != COIN_CLASS)
1218 add_to_migration(obj);
1221 obj->owornmask = (long)toloc;
1223 /* number of fallen objects */
1227 if (dct && cansee(x,y)) { /* at least one object fell */
1228 const char *what = (dct == 1L ? "object falls" : "objects fall");
1231 pline("From the impact, %sother %s.",
1232 dct == oct ? "the " : dct == 1L ? "an" : "", what);
1233 else if (oct == dct)
1234 pline("%s adjacent %s %s.",
1235 dct == 1L ? "The" : "All the", what, gate_str);
1237 pline("%s adjacent %s %s.",
1238 dct == 1L ? "One of the" : "Some of the",
1239 dct == 1L ? "objects falls" : what, gate_str);
1242 if(costly && shkp && price) {
1243 if(ESHK(shkp)->robbed > robbed) {
1244 You("removed %ld %s worth of goods!", price, currency(price));
1245 if(cansee(shkp->mx, shkp->my)) {
1246 if(ESHK(shkp)->customer[0] == 0)
1247 (void) strncpy(ESHK(shkp)->customer,
1250 pline("%s is infuriated!", Monnam(shkp));
1251 else pline("\"%s, you are a thief!\"", plname);
1252 } else You_hear("a scream, \"Thief!\"");
1254 (void) angry_guards(FALSE);
1257 if(ESHK(shkp)->debit > debit) {
1258 long amt = (ESHK(shkp)->debit - debit);
1259 You("owe %s %ld %s for goods lost.",
1261 amt, currency(amt));
1267 /* NOTE: ship_object assumes otmp was FREED from fobj or invent.
1268 * <x,y> is the point of drop. otmp is _not_ an <x,y> resident:
1269 * otmp is either a kicked, dropped, or thrown object.
1272 ship_object(otmp, x, y, shop_floor_obj)
1275 boolean shop_floor_obj;
1282 boolean nodrop, unpaid, container, impact = FALSE;
1285 if (!otmp) return(FALSE);
1286 if ((toloc = down_gate(x, y)) == MIGR_NOWHERE) return(FALSE);
1287 drop_to(&cc, toloc);
1288 if (!cc.y) return(FALSE);
1290 /* objects other than attached iron ball always fall down ladder,
1291 but have a chance of staying otherwise */
1292 nodrop = (otmp == uball) || (otmp == uchain) ||
1293 (toloc != MIGR_LADDER_UP && rn2(3));
1295 container = Has_contents(otmp);
1296 unpaid = (otmp->unpaid || (container && count_unpaid(otmp->cobj)));
1299 for(obj = level.objects[x][y]; obj; obj = obj->nexthere)
1300 if(obj != otmp) n += obj->quan;
1301 if(n) impact = TRUE;
1303 /* boulders never fall through trap doors, but they might knock
1304 other things down before plugging the hole */
1305 if (otmp->otyp == BOULDER &&
1306 ((t = t_at(x, y)) != 0) &&
1307 (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) {
1308 if (impact) impact_drop(otmp, x, y, 0);
1309 return FALSE; /* let caller finish the drop */
1313 otransit_msg(otmp, nodrop, n);
1316 if (impact) impact_drop(otmp, x, y, 0);
1320 if(unpaid || shop_floor_obj) {
1322 subfrombill(otmp, shop_keeper(*u.ushops));
1323 (void)stolen_value(otmp, u.ux, u.uy, TRUE, FALSE);
1327 (void)stolen_value(otmp, ox, oy,
1328 (costly_spot(u.ux, u.uy) &&
1329 index(u.urooms, *in_rooms(ox, oy, SHOPBASE))),
1332 /* set otmp->no_charge to 0 */
1334 picked_container(otmp); /* happens to do the right thing */
1335 if(otmp->oclass != COIN_CLASS)
1336 otmp->no_charge = 0;
1339 if (otmp == uwep) setuwep((struct obj *)0);
1340 if (otmp == uquiver) setuqwep((struct obj *)0);
1341 if (otmp == uswapwep) setuswapwep((struct obj *)0);
1343 /* some things break rather than ship */
1344 if (breaktest(otmp)) {
1347 if (objects[otmp->otyp].oc_material == GLASS
1349 || otmp->otyp == EXPENSIVE_CAMERA
1352 if (otmp->otyp == MIRROR)
1356 /* penalty for breaking eggs laid by you */
1357 if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
1358 change_luck((schar) -min(otmp->quan, 5L));
1361 You_hear("a muffled %s.",result);
1362 obj_extract_self(otmp);
1363 obfree(otmp, (struct obj *) 0);
1367 add_to_migration(otmp);
1370 otmp->owornmask = (long)toloc;
1371 /* boulder from rolling boulder trap, no longer part of the trap */
1372 if (otmp->otyp == BOULDER) otmp->otrapped = 0;
1375 /* the objs impacted may be in a shop other than
1376 * the one in which the hero is located. another
1377 * check for a shk is made in impact_drop. it is, e.g.,
1378 * possible to kick/throw an object belonging to one
1379 * shop into another shop through a gap in the wall,
1380 * and cause objects belonging to the other shop to
1381 * fall down a trap door--thereby getting two shopkeepers
1382 * angry at the hero in one shot.
1384 impact_drop(otmp, x, y, 0);
1393 register struct obj *otmp, *otmp2;
1394 register int nx, ny;
1397 for (otmp = migrating_objs; otmp; otmp = otmp2) {
1399 if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue;
1401 obj_extract_self(otmp);
1402 where = otmp->owornmask; /* destination code */
1403 otmp->owornmask = 0L;
1405 switch ((int)where) {
1406 case MIGR_STAIRS_UP: nx = xupstair, ny = yupstair;
1408 case MIGR_LADDER_UP: nx = xupladder, ny = yupladder;
1410 case MIGR_SSTAIRS: nx = sstairs.sx, ny = sstairs.sy;
1412 case MIGR_NEAR_PLAYER: nx = u.ux, ny = u.uy;
1415 case MIGR_RANDOM: nx = ny = 0;
1419 place_object(otmp, nx, ny);
1421 (void)scatter(nx, ny, rnd(2), 0, otmp);
1422 } else { /* random location */
1423 /* set dummy coordinates because there's no
1424 current position for rloco() to update */
1425 otmp->ox = otmp->oy = 0;
1432 otransit_msg(otmp, nodrop, num)
1433 register struct obj *otmp;
1434 register boolean nodrop;
1439 Sprintf(obuf, "%s%s",
1440 (otmp->otyp == CORPSE &&
1441 type_is_pname(&mons[otmp->corpsenm])) ? "" : "The ",
1444 if(num) { /* means: other objects are impacted */
1445 Sprintf(eos(obuf), " %s %s object%s",
1446 otense(otmp, "hit"),
1447 num == 1L ? "another" : "other",
1448 num > 1L ? "s" : "");
1450 Sprintf(eos(obuf), ".");
1452 Sprintf(eos(obuf), " and %s %s.",
1453 otense(otmp, "fall"), gate_str);
1456 pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str);
1459 /* migration destination for objects which fall down to next level */
1467 /* this matches the player restriction in goto_level() */
1468 if (on_level(&u.uz, &qstart_level) && !ok_to_quest())
1469 return MIGR_NOWHERE;
1471 if ((xdnstair == x && ydnstair == y) ||
1472 (sstairs.sx == x && sstairs.sy == y && !sstairs.up)) {
1473 gate_str = "down the stairs";
1474 return (xdnstair == x && ydnstair == y) ?
1475 MIGR_STAIRS_UP : MIGR_SSTAIRS;
1477 if (xdnladder == x && ydnladder == y) {
1478 gate_str = "down the ladder";
1479 return MIGR_LADDER_UP;
1482 if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen) &&
1483 (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) {
1484 gate_str = (ttmp->ttyp == TRAPDOOR) ?
1485 "through the trap door" : "through the hole";
1488 return MIGR_NOWHERE;