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. */ 4 5#include "hack.h" 6#include "eshk.h" 7 8#define is_bigfoot(x) ((x) == &mons[PM_SASQUATCH]) 9#define martial() (martial_bonus() || is_bigfoot(youmonst.data) || \ 10 (uarmf && uarmf->otyp == KICKING_BOOTS)) 11 12static NEARDATA struct rm *maploc; 13static NEARDATA const char *gate_str; 14 15extern boolean notonhead; /* for long worms */ 16 17STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P)); 18STATIC_DCL void FDECL(kick_monster, (XCHAR_P, XCHAR_P)); 19STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P)); 20STATIC_DCL char *FDECL(kickstr, (char *)); 21STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long)); 22STATIC_DCL void FDECL(drop_to, (coord *,SCHAR_P)); 23 24static NEARDATA struct obj *kickobj; 25 26static const char kick_passes_thru[] = "kick passes harmlessly through"; 27 28STATIC_OVL void 29kickdmg(mon, clumsy) 30register struct monst *mon; 31register boolean clumsy; 32{ 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; 38 39 if (uarmf && uarmf->otyp == KICKING_BOOTS) 40 dmg += 5; 41 42 /* excessive wt affects dex, so it affects dmg */ 43 if (clumsy) dmg /= 2; 44 45 /* kicking a dragon or an elephant will not harm it */ 46 if (thick_skinned(mon->data)) dmg = 0; 47 48 /* attacking a shade is useless */ 49 if (mon->data == &mons[PM_SHADE]) 50 dmg = 0; 51 52 if ((is_undead(mon->data) || is_demon(mon->data)) && uarmf && 53 uarmf->blessed) 54 blessed_foot_damage = 1; 55 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 */ 60 return; 61 } 62 63 if(mon->m_ap_type) seemimic(mon); 64 65 check_caitiff(mon); 66 67 /* squeeze some guilt feelings... */ 68 if(mon->mtame) { 69 abuse_dog(mon); 70 if (mon->mtame) 71 monflee(mon, (dmg ? rnd(dmg) : 1), FALSE, FALSE); 72 else 73 mon->mflee = 0; 74 } 75 76 if (dmg > 0) { 77 /* convert potential damage to actual damage */ 78 dmg = rnd(dmg); 79 if (martial()) { 80 if (dmg > 1) kick_skill = P_MARTIAL_ARTS; 81 dmg += rn2(ACURR(A_DEX)/2 + 1); 82 } 83 /* a good kick exercises your dex */ 84 exercise(A_DEX, TRUE); 85 } 86 if (blessed_foot_damage) dmg += rnd(4); 87 if (uarmf) dmg += uarmf->spe; 88 dmg += u.udaminc; /* add ring(s) of increase damage */ 89 if (dmg > 0) 90 mon->mhp -= dmg; 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 */ 94 mdx = mon->mx + u.dx; 95 mdy = mon->my + u.dy; 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); 103 set_apparxy(mon); 104 if (mintrap(mon) == 2) trapkilled = TRUE; 105 } 106 } 107 } 108 109 (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK); 110 if (mon->mhp <= 0 && !trapkilled) killed(mon); 111 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); 115} 116 117STATIC_OVL void 118kick_monster(x, y) 119register xchar x, y; 120{ 121 register boolean clumsy = FALSE; 122 register struct monst *mon = m_at(x, y); 123 register int i, j; 124 125 bhitpos.x = x; 126 bhitpos.y = y; 127 if (attack_checks(mon, (struct obj *)0)) return; 128 setmangry(mon); 129 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. 135 */ 136 if (Upolyd && attacktype(youmonst.data, AT_KICK)) { 137 struct attack *uattk; 138 int sum; 139 schar tmp = find_roll_to_hit(mon); 140 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; 145 146 uattk = &youmonst.data->mattk[i]; 147 /* we only care about kicking attacks here */ 148 if (uattk->aatyp != AT_KICK) continue; 149 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); 160 if (sum == 2) 161 break; /* Defender died */ 162 } else { 163 missum(mon, uattk); 164 (void)passive(mon, 0, 1, AT_KICK); 165 } 166 } 167 return; 168 } 169 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); 175 return; 176 } 177 178 i = -inv_weight(); 179 j = weight_cap(); 180 181 if(i < (j*3)/10) { 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); 186 return; 187 } 188 if(i < j/10) clumsy = TRUE; 189 else if(!rn2((i < j/5) ? 2 : 3)) clumsy = TRUE; 190 } 191 192 if(Fumbling) clumsy = TRUE; 193 194 else if(uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25)) 195 clumsy = TRUE; 196doit: 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); 207 return; 208 } else { 209 mnexto(mon); 210 if(mon->mx != x || mon->my != y) { 211 if(glyph_is_invisible(levl[x][y].glyph)) { 212 unmap_object(x, y); 213 newsym(x, y); 214 } 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)) ? 220 "slides" : "jumps"), 221 clumsy ? "easily" : "nimbly", 222 clumsy ? "clumsy " : ""); 223 (void) passive(mon, FALSE, 1, AT_KICK); 224 return; 225 } 226 } 227 } 228 kickdmg(mon, clumsy); 229} 230 231/* 232 * Return TRUE if caught (the gold taken care of), FALSE otherwise. 233 * The gold object is *not* attached to the fobj chain! 234 */ 235boolean 236ghitm(mtmp, gold) 237register struct monst *mtmp; 238register struct obj *gold; 239{ 240 boolean msg_given = FALSE; 241 242 if(!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest 243 && !is_mercenary(mtmp->data)) { 244 wakeup(mtmp); 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)); 250 msg_given = TRUE; 251 } 252 } else { 253#ifdef GOLDOBJ 254 long value = gold->quan * objects[gold->otyp].oc_cost; 255#endif 256 mtmp->msleeping = 0; 257 mtmp->meating = 0; 258 if(!rn2(4)) setmangry(mtmp); /* not always pleasing */ 259 260 /* greedy monsters catch gold */ 261 if (cansee(mtmp->mx, mtmp->my)) 262 pline("%s catches the gold.", Monnam(mtmp)); 263#ifndef GOLDOBJ 264 mtmp->mgold += gold->quan; 265#endif 266 if (mtmp->isshk) { 267 long robbed = ESHK(mtmp)->robbed; 268 269 if (robbed) { 270#ifndef GOLDOBJ 271 robbed -= gold->quan; 272#else 273 robbed -= value; 274#endif 275 if (robbed < 0) robbed = 0; 276 pline_The("amount %scovers %s recent losses.", 277 !robbed ? "" : "partially ", 278 mhis(mtmp)); 279 ESHK(mtmp)->robbed = robbed; 280 if(!robbed) 281 make_happy_shk(mtmp, FALSE); 282 } else { 283 if(mtmp->mpeaceful) { 284#ifndef GOLDOBJ 285 ESHK(mtmp)->credit += gold->quan; 286#else 287 ESHK(mtmp)->credit += value; 288#endif 289 You("have %ld %s in credit.", 290 ESHK(mtmp)->credit, 291 currency(ESHK(mtmp)->credit)); 292 } else verbalize("Thanks, scum!"); 293 } 294 } else if (mtmp->ispriest) { 295 if (mtmp->mpeaceful) 296 verbalize("Thank you for your contribution."); 297 else verbalize("Thanks, scum!"); 298 } else if (is_mercenary(mtmp->data)) { 299 long goldreqd = 0L; 300 301 if (rn2(3)) { 302 if (mtmp->data == &mons[PM_SOLDIER]) 303 goldreqd = 100L; 304 else if (mtmp->data == &mons[PM_SERGEANT]) 305 goldreqd = 250L; 306 else if (mtmp->data == &mons[PM_LIEUTENANT]) 307 goldreqd = 500L; 308 else if (mtmp->data == &mons[PM_CAPTAIN]) 309 goldreqd = 750L; 310 311 if (goldreqd) { 312#ifndef GOLDOBJ 313 if (gold->quan > goldreqd + 314 (u.ugold + u.ulevel*rn2(5))/ACURR(A_CHA)) 315#else 316 if (value > goldreqd + 317 (money_cnt(invent) + u.ulevel*rn2(5))/ACURR(A_CHA)) 318#endif 319 mtmp->mpeaceful = TRUE; 320 } 321 } 322 if (mtmp->mpeaceful) 323 verbalize("That should do. Now beat it!"); 324 else verbalize("That's not enough, coward!"); 325 } 326 327#ifndef GOLDOBJ 328 dealloc_obj(gold); 329#else 330 add_to_minv(mtmp, gold); 331#endif 332 return TRUE; 333 } 334 335 if (!msg_given) miss(xname(gold), mtmp); 336 return FALSE; 337} 338 339/* container is kicked, dropped, thrown or otherwise impacted by player. 340 * Assumes container is on floor. Checks contents for possible damage. */ 341void 342container_impact_dmg(obj) 343struct obj *obj; 344{ 345 struct monst *shkp; 346 struct obj *otmp, *otmp2; 347 long loss = 0L; 348 boolean costly, insider; 349 xchar x = obj->ox, y = obj->oy; 350 351 /* only consider normal containers */ 352 if (!Is_container(obj) || Is_mbag(obj)) return; 353 354 costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && 355 costly_spot(x, y)); 356 insider = (*u.ushops && inside_shop(u.ux, u.uy) && 357 *in_rooms(x, y, SHOPBASE) == *u.ushops); 358 359 for (otmp = obj->cobj; otmp; otmp = otmp2) { 360 const char *result = (char *)0; 361 362 otmp2 = otmp->nobj; 363 if (objects[otmp->otyp].oc_material == GLASS && 364 otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) { 365 result = "shatter"; 366 } else if (otmp->otyp == EGG && !rn2(3)) { 367 result = "cracking"; 368 } 369 if (result) { 370 if (otmp->otyp == MIRROR) change_luck(-2); 371 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) 375 change_luck(-1); 376 You_hear("a muffled %s.", result); 377 if (costly) 378 loss += stolen_value(otmp, x, y, 379 (boolean)shkp->mpeaceful, TRUE); 380 if (otmp->quan > 1L) 381 useup(otmp); 382 else { 383 obj_extract_self(otmp); 384 obfree(otmp, (struct obj *) 0); 385 } 386 } 387 } 388 if (costly && loss) { 389 if (!insider) { 390 You("caused %ld %s worth of damage!", loss, currency(loss)); 391 make_angry_shk(shkp, x, y); 392 } else { 393 You("owe %s %ld %s for objects destroyed.", 394 mon_nam(shkp), loss, currency(loss)); 395 } 396 } 397} 398 399STATIC_OVL int 400kick_object(x, y) 401xchar x, y; 402{ 403 int range; 404 register struct monst *mon, *shkp; 405 struct trap *trap; 406 char bhitroom; 407 boolean costly, isgold, slide = FALSE; 408 409 /* if a pile, the "top" object gets kicked */ 410 kickobj = level.objects[x][y]; 411 412 /* kickobj should always be set due to conditions of call */ 413 if(!kickobj || kickobj->otyp == BOULDER 414 || kickobj == uball || kickobj == uchain) 415 return(0); 416 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"); 425 return 1; 426 } 427 428 if(Fumbling && !rn2(3)) { 429 Your("clumsy kick missed."); 430 return(1); 431 } 432 433 if(kickobj->otyp == CORPSE && touch_petrifies(&mons[kickobj->corpsenm]) 434 && !Stone_resistance && !uarmf) { 435 char kbuf[BUFSZ]; 436 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))); 445 killer = kbuf; 446 done(STONING); 447 } 448 } 449 450 /* range < 2 means the object will not move. */ 451 /* maybe dexterity should also figure here. */ 452 range = (int)((ACURRSTR)/2 - kickobj->owt/40); 453 454 if(martial()) range += rnd(3); 455 456 if (is_pool(x, y)) { 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 */ 459 } else { 460 if (is_ice(x, y)) range += rnd(3), slide = TRUE; 461 if (kickobj->greased) range += rnd(3), slide = TRUE; 462 } 463 464 /* Mjollnir is magically too heavy to kick */ 465 if(kickobj->oartifact == ART_MJOLLNIR) range = 1; 466 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)) 469 range = 1; 470 471 costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && 472 costly_spot(x, y)); 473 isgold = (kickobj->oclass == COIN_CLASS); 474 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)) { 478 if (Blind) 479 pline("It doesn't come loose."); 480 else 481 pline("%s %sn't come loose.", 482 The(distant_name(kickobj, xname)), 483 otense(kickobj, "do")); 484 return (!rn2(3) || martial()); 485 } 486 if (Blind) 487 pline("It comes loose."); 488 else 489 pline("%s %s loose.", 490 The(distant_name(kickobj, xname)), 491 otense(kickobj, "come")); 492 obj_extract_self(kickobj); 493 newsym(x, y); 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); 499 stackobj(kickobj); 500 newsym(u.ux, u.uy); 501 } 502 return 1; 503 } 504 505 /* a box gets a chance of breaking open here */ 506 if(Is_box(kickobj)) { 507 boolean otrp = kickobj->otrapped; 508 509 if(range < 2) pline("THUD!"); 510 511 container_impact_dmg(kickobj); 512 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); 519 return(1); 520 } 521 } else { 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); 525 return(1); 526 } 527 } 528 if(range < 2) return(1); 529 /* else let it fall through to the next cases... */ 530 } 531 532 /* fragile objects should not be kicked */ 533 if (hero_breaks(kickobj, kickobj->ox, kickobj->oy, FALSE)) return 1; 534 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 538 */ 539 if(range < 2 || (isgold && kickobj->quan > 300L)) { 540 if(!Is_box(kickobj)) pline("Thump!"); 541 return(!rn2(3) || martial()); 542 } 543 544 if (kickobj->quan > 1L && !isgold) kickobj = splitobj(kickobj, 1L); 545 546 if (slide && !Blind) 547 pline("Whee! %s %s across the %s.", Doname2(kickobj), 548 otense(kickobj, "slide"), surface(x,y)); 549 550 obj_extract_self(kickobj); 551 (void) snuff_candle(kickobj); 552 newsym(x, y); 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, 556 kickobj); 557 558 if(mon) { 559 if (mon->isshk && 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? */ 565 return(1); 566 } 567 568 /* the object might have fallen down a hole */ 569 if (kickobj->where == OBJ_MIGRATING) { 570 if (costly) { 571 if(isgold) 572 costly_gold(x, y, kickobj->quan); 573 else (void)stolen_value(kickobj, x, y, 574 (boolean)shkp->mpeaceful, FALSE); 575 } 576 return 1; 577 } 578 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)) { 582 if(isgold) 583 costly_gold(x, y, kickobj->quan); 584 else (void)stolen_value(kickobj, x, y, 585 (boolean)shkp->mpeaceful, FALSE); 586 } 587 588 if(flooreffects(kickobj,bhitpos.x,bhitpos.y,"fall")) return(1); 589 place_object(kickobj, bhitpos.x, bhitpos.y); 590 stackobj(kickobj); 591 newsym(kickobj->ox, kickobj->oy); 592 return(1); 593} 594 595STATIC_OVL char * 596kickstr(buf) 597char *buf; 598{ 599 const char *what; 600 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"; 609#ifdef SINKS 610 else if (IS_SINK(maploc->typ)) what = "a sink"; 611#endif 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); 619} 620 621int 622dokick() 623{ 624 int x, y; 625 int avrg_attrib; 626 register struct monst *mtmp; 627 boolean no_kick = FALSE; 628 char buf[BUFSZ]; 629 630 if (nolimbs(youmonst.data) || slithy(youmonst.data)) { 631 You("have no legs to kick with."); 632 no_kick = TRUE; 633 } else if (verysmall(youmonst.data)) { 634 You("are too small to do any kicking."); 635 no_kick = TRUE; 636#ifdef STEED 637 } else if (u.usteed) { 638 if (yn_function("Kick your steed?", ynchars, 'y') == 'y') { 639 You("kick %s.", mon_nam(u.usteed)); 640 kick_steed(); 641 return 1; 642 } else { 643 return 0; 644 } 645#endif 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); 650 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"); 656 no_kick = TRUE; 657 } else if (near_capacity() > SLT_ENCUMBER) { 658 Your("load is too heavy to balance yourself for a kick."); 659 no_kick = TRUE; 660 } else if (youmonst.data->mlet == S_LIZARD) { 661 Your("legs cannot kick effectively."); 662 no_kick = TRUE; 663 } else if (u.uinwater && !rn2(2)) { 664 Your("slow motion kick doesn't hit anything."); 665 no_kick = TRUE; 666 } else if (u.utrap) { 667 switch (u.utraptype) { 668 case TT_PIT: 669 pline("There's not enough room to kick down here."); 670 break; 671 case TT_WEB: 672 case TT_BEARTRAP: 673 You_cant("move your %s!", body_part(LEG)); 674 break; 675 default: 676 break; 677 } 678 no_kick = TRUE; 679 } 680 681 if (no_kick) { 682 /* ignore direction typed before player notices kick failed */ 683 display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */ 684 return 0; 685 } 686 687 if(!getdir((char *)0)) return(0); 688 if(!u.dx && !u.dy) return(0); 689 690 x = u.ux + u.dx; 691 y = u.uy + u.dy; 692 693 /* KMH -- Kicking boots always succeed */ 694 if (uarmf && uarmf->otyp == KICKING_BOOTS) 695 avrg_attrib = 99; 696 else 697 avrg_attrib = (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3; 698 699 if(u.uswallow) { 700 switch(rn2(3)) { 701 case 0: You_cant("move your %s!", body_part(LEG)); 702 break; 703 case 1: if (is_animal(u.ustuck->data)) { 704 pline("%s burps loudly.", Monnam(u.ustuck)); 705 break; 706 } 707 default: Your("feeble kick has no effect."); break; 708 } 709 return(1); 710 } 711 if (Levitation) { 712 int xx, yy; 713 714 xx = u.ux - u.dx; 715 yy = u.uy - u.dy; 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? 719 */ 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."); 724 return(0); 725 } 726 } 727 728 wake_nearby(); 729 u_wipe_engr(2); 730 731 maploc = &levl[x][y]; 732 733 /* The next five tests should stay in */ 734 /* their present order: monsters, pools, */ 735 /* objects, non-doors, doors. */ 736 737 if(MON_AT(x, y)) { 738 struct permonst *mdat; 739 740 mtmp = m_at(x, y); 741 mdat = mtmp->data; 742 if (!mtmp->mpeaceful || !canspotmon(mtmp)) 743 flags.forcefight = TRUE; /* attack even if invisible */ 744 kick_monster(x, y); 745 flags.forcefight = FALSE; 746 /* see comment in attack_checks() */ 747 if (!DEADMONSTER(mtmp) && 748 !canspotmon(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)) 754 map_invisible(x, y); 755 if((Is_airlevel(&u.uz) || Levitation) && flags.move) { 756 int range; 757 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; 761 762 if(range < 1) range = 1; 763 hurtle(-u.dx, -u.dy, range, TRUE); 764 } 765 return(1); 766 } 767 if (glyph_is_invisible(levl[x][y].glyph)) { 768 unmap_object(x, y); 769 newsym(x, y); 770 } 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."); 774 return 1; 775 } 776 777 kickobj = (struct obj *)0; 778 if (OBJ_AT(x, y) && 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 */ 784 return(1); 785 } 786 goto ouch; 787 } 788 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; 805 if (Blind) 806 feel_location(x,y); /* we know it's gone */ 807 else 808 newsym(x,y); 809 if (maploc->doormask == D_ISOPEN || 810 maploc->doormask == D_NODOOR) 811 unblock_point(x,y); /* vision */ 812 return(1); 813 } else goto ouch; 814 } 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); 819 maploc->typ = CORR; 820 if (Blind) 821 feel_location(x,y); /* we know it's gone */ 822 else 823 newsym(x,y); 824 unblock_point(x,y); /* vision */ 825 return(1); 826 } else goto ouch; 827 } 828 if(IS_THRONE(maploc->typ)) { 829 register int i; 830 if(Levitation) goto dumb; 831 if((Luck < 0 || maploc->doormask) && !rn2(3)) { 832 maploc->typ = ROOM; 833 maploc->doormask = 0; /* don't leave loose ends.. */ 834 (void) mkgold((long)rnd(200), x, y); 835 if (Blind) 836 pline("CRASH! You destroy it."); 837 else { 838 pline("CRASH! You destroy the throne."); 839 newsym(x, y); 840 } 841 exercise(A_DEX, TRUE); 842 return(1); 843 } else if(Luck > 0 && !rn2(3) && !maploc->looted) { 844 (void) mkgold((long) rn1(201, 300), x, y); 845 i = Luck + 1; 846 if(i > 6) i = 6; 847 while(i--) 848 (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, 849 LUCKSTONE-1), x, y, FALSE, TRUE); 850 if (Blind) 851 You("kick %s loose!", something); 852 else { 853 You("kick loose some ornamental coins and gems!"); 854 newsym(x, y); 855 } 856 /* prevent endless milking */ 857 maploc->looted = T_LOOTED; 858 return(1); 859 } else if (!rn2(4)) { 860 if(dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) { 861 fall_through(FALSE); 862 return(1); 863 } else goto ouch; 864 } 865 goto ouch; 866 } 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; 871 altar_wrath(x, y); 872 exercise(A_DEX, TRUE); 873 return(1); 874 } 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 */ 880 if(uarmf && rn2(3)) 881 if (!rust_dmg(uarmf, "metal boots", 1, FALSE, &youmonst)) { 882 Your("boots get wet."); 883 /* could cause short-lived fumbling here */ 884 } 885 exercise(A_DEX, TRUE); 886 return(1); 887 } 888 if(IS_GRAVE(maploc->typ) || maploc->typ == IRONBARS) 889 goto ouch; 890 if(IS_TREE(maploc->typ)) { 891 struct obj *treefruit; 892 /* nothing, fruit or trouble? 75:23.5:1.5% */ 893 if (rn2(3)) { 894 if ( !rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE) ) 895 You_hear("a low buzzing."); /* a warning */ 896 goto ouch; 897 } 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)); 905 else 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); 916 } 917 exercise(A_DEX, TRUE); 918 exercise(A_WIS, TRUE); /* discovered a new food source! */ 919 newsym(x, y); 920 maploc->looted |= TREE_LOOTED; 921 return(1); 922 } else if (!(maploc->looted & TREE_SWARM)) { 923 int cnt = rnl(4) + 2; 924 int made = 0; 925 coord mm; 926 mm.x = x; mm.y = y; 927 while (cnt--) { 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)) 931 made++; 932 } 933 if ( made ) 934 pline("You've attracted the tree's former occupants!"); 935 else 936 You("smell stale honey."); 937 maploc->looted |= TREE_SWARM; 938 return(1); 939 } 940 goto ouch; 941 } 942#ifdef SINKS 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; 947 948 if(Levitation) goto dumb; 949 if(rn2(5)) { 950 if(flags.soundok) 951 pline("Klunk! The pipes vibrate noisily."); 952 else pline("Klunk!"); 953 exercise(A_DEX, TRUE); 954 return(1); 955 } else if(!(maploc->looted & S_LPUDDING) && !rn2(3) && 956 !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) { 957 if (Blind) 958 You_hear("a gushing sound."); 959 else 960 pline("A %s ooze gushes up from the drain!", 961 hcolor(NH_BLACK)); 962 (void) makemon(&mons[PM_BLACK_PUDDING], 963 x, y, NO_MM_FLAGS); 964 exercise(A_DEX, TRUE); 965 newsym(x,y); 966 maploc->looted |= S_LPUDDING; 967 return(1); 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 : 972 "The dish washer")); 973 if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS)) 974 newsym(x,y); 975 maploc->looted |= S_LDWASHER; 976 exercise(A_DEX, TRUE); 977 return(1); 978 } else if(!rn2(3)) { 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 */ 983 if (!Blind) 984 You("see a ring shining in its midst."); 985 (void) mkobj_at(RING_CLASS, x, y, TRUE); 986 newsym(x, y); 987 exercise(A_DEX, TRUE); 988 exercise(A_WIS, TRUE); /* a discovery! */ 989 maploc->looted |= S_LRING; 990 } 991 return(1); 992 } 993 goto ouch; 994 } 995#endif 996 if (maploc->typ == STAIRS || maploc->typ == LADDER || 997 IS_STWALL(maploc->typ)) { 998 if(!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN) 999 goto dumb; 1000ouch: 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]; 1010 } 1011 if(!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); 1012 losehp(rnd(ACURR(A_CON) > 15 ? 3 : 5), kickstr(buf), 1013 KILLED_BY); 1014 if(Is_airlevel(&u.uz) || Levitation) 1015 hurtle(-u.dx, -u.dy, rn1(2,4), TRUE); /* assume it's heavy */ 1016 return(1); 1017 } 1018 goto dumb; 1019 } 1020 1021 if(maploc->doormask == D_ISOPEN || 1022 maploc->doormask == D_BROKEN || 1023 maploc->doormask == D_NODOOR) { 1024dumb: 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); 1029 } else { 1030 pline("Dumb move! You strain a muscle."); 1031 exercise(A_STR, FALSE); 1032 set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); 1033 } 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 */ 1037 } 1038 return(0); 1039 } 1040 1041 /* not enough leverage to kick open doors while levitating */ 1042 if(Levitation) goto ouch; 1043 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; 1058 } else { 1059 pline("As you kick the door, it crashes open!"); 1060 exercise(A_STR, TRUE); 1061 maploc->doormask = D_BROKEN; 1062 } 1063 if (Blind) 1064 feel_location(x,y); /* we know we broke it */ 1065 else 1066 newsym(x,y); 1067 unblock_point(x,y); /* vision */ 1068 if (shopdoor) { 1069 add_damage(x, y, 400L); 1070 pay_for_damage("break", FALSE); 1071 } 1072 if (in_town(x, y)) 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) && 1078 mtmp->mpeaceful) { 1079 if (canspotmon(mtmp)) 1080 pline("%s yells:", Amonnam(mtmp)); 1081 else 1082 You_hear("someone yell:"); 1083 verbalize("Halt, thief! You're under arrest!"); 1084 (void) angry_guards(FALSE); 1085 break; 1086 } 1087 } 1088 } else { 1089 if (Blind) feel_location(x,y); /* we know we hit it */ 1090 exercise(A_STR, TRUE); 1091 pline("WHAMMM!!!"); 1092 if (in_town(x, y)) 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)); 1100 else 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); 1105 } else { 1106 verbalize("Hey, stop damaging that door!"); 1107 levl[x][y].looted |= D_WARNED; 1108 } 1109 break; 1110 } 1111 } 1112 } 1113 return(1); 1114} 1115 1116STATIC_OVL void 1117drop_to(cc, loc) 1118coord *cc; 1119schar loc; 1120{ 1121 /* cover all the MIGR_xxx choices generated by down_gate() */ 1122 switch (loc) { 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; 1127 break; 1128 } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) { 1129 cc->y = cc->x = 0; 1130 break; 1131 } /* else fall to the next cases */ 1132 case MIGR_STAIRS_UP: 1133 case MIGR_LADDER_UP: 1134 cc->x = u.uz.dnum; 1135 cc->y = u.uz.dlevel + 1; 1136 break; 1137 case MIGR_SSTAIRS: 1138 cc->x = sstairs.tolev.dnum; 1139 cc->y = sstairs.tolev.dlevel; 1140 break; 1141 default: 1142 case MIGR_NOWHERE: 1143 /* y==0 means "nowhere", in which case x doesn't matter */ 1144 cc->y = cc->x = 0; 1145 break; 1146 } 1147} 1148 1149void 1150impact_drop(missile, x, y, dlev) 1151struct obj *missile; 1152xchar x, y, dlev; 1153{ 1154 schar toloc; 1155 register struct obj *obj, *obj2; 1156 register struct monst *shkp; 1157 long oct, dct, price, debit, robbed; 1158 boolean angry, costly, isrock; 1159 coord cc; 1160 1161 if(!OBJ_AT(x, y)) return; 1162 1163 toloc = down_gate(x, y); 1164 drop_to(&cc, toloc); 1165 if (!cc.y) return; 1166 1167 if (dlev) { 1168 /* send objects next to player falling through trap door. 1169 * checked in obj_delivery(). 1170 */ 1171 toloc = MIGR_NEAR_PLAYER; 1172 cc.y = dlev; 1173 } 1174 1175 costly = costly_spot(x, y); 1176 price = debit = robbed = 0L; 1177 angry = FALSE; 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. 1184 */ 1185 if(costly) { 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; 1190 } 1191 } 1192 1193 isrock = (missile && missile->otyp == ROCK); 1194 oct = dct = 0L; 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 */ 1199 oct += obj->quan; 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); 1205 1206 if(costly) { 1207 price += stolen_value(obj, x, y, 1208 (costly_spot(u.ux, u.uy) && 1209 index(u.urooms, *in_rooms(x, y, SHOPBASE))), 1210 TRUE); 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) 1215 obj->no_charge = 0; 1216 } 1217 1218 add_to_migration(obj); 1219 obj->ox = cc.x; 1220 obj->oy = cc.y; 1221 obj->owornmask = (long)toloc; 1222 1223 /* number of fallen objects */ 1224 dct += obj->quan; 1225 } 1226 1227 if (dct && cansee(x,y)) { /* at least one object fell */ 1228 const char *what = (dct == 1L ? "object falls" : "objects fall"); 1229 1230 if (missile) 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); 1236 else 1237 pline("%s adjacent %s %s.", 1238 dct == 1L ? "One of the" : "Some of the", 1239 dct == 1L ? "objects falls" : what, gate_str); 1240 } 1241 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, 1248 plname, PL_NSIZ); 1249 if(angry) 1250 pline("%s is infuriated!", Monnam(shkp)); 1251 else pline("\"%s, you are a thief!\"", plname); 1252 } else You_hear("a scream, \"Thief!\""); 1253 hot_pursuit(shkp); 1254 (void) angry_guards(FALSE); 1255 return; 1256 } 1257 if(ESHK(shkp)->debit > debit) { 1258 long amt = (ESHK(shkp)->debit - debit); 1259 You("owe %s %ld %s for goods lost.", 1260 Monnam(shkp), 1261 amt, currency(amt)); 1262 } 1263 } 1264 1265} 1266 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. 1270 */ 1271boolean 1272ship_object(otmp, x, y, shop_floor_obj) 1273xchar x, y; 1274struct obj *otmp; 1275boolean shop_floor_obj; 1276{ 1277 schar toloc; 1278 xchar ox, oy; 1279 coord cc; 1280 struct obj *obj; 1281 struct trap *t; 1282 boolean nodrop, unpaid, container, impact = FALSE; 1283 long n = 0L; 1284 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); 1289 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)); 1294 1295 container = Has_contents(otmp); 1296 unpaid = (otmp->unpaid || (container && count_unpaid(otmp->cobj))); 1297 1298 if(OBJ_AT(x, y)) { 1299 for(obj = level.objects[x][y]; obj; obj = obj->nexthere) 1300 if(obj != otmp) n += obj->quan; 1301 if(n) impact = TRUE; 1302 } 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 */ 1310 } 1311 1312 if (cansee(x, y)) 1313 otransit_msg(otmp, nodrop, n); 1314 1315 if (nodrop) { 1316 if (impact) impact_drop(otmp, x, y, 0); 1317 return(FALSE); 1318 } 1319 1320 if(unpaid || shop_floor_obj) { 1321 if(unpaid) { 1322 subfrombill(otmp, shop_keeper(*u.ushops)); 1323 (void)stolen_value(otmp, u.ux, u.uy, TRUE, FALSE); 1324 } else { 1325 ox = otmp->ox; 1326 oy = otmp->oy; 1327 (void)stolen_value(otmp, ox, oy, 1328 (costly_spot(u.ux, u.uy) && 1329 index(u.urooms, *in_rooms(ox, oy, SHOPBASE))), 1330 FALSE); 1331 } 1332 /* set otmp->no_charge to 0 */ 1333 if(container) 1334 picked_container(otmp); /* happens to do the right thing */ 1335 if(otmp->oclass != COIN_CLASS) 1336 otmp->no_charge = 0; 1337 } 1338 1339 if (otmp == uwep) setuwep((struct obj *)0); 1340 if (otmp == uquiver) setuqwep((struct obj *)0); 1341 if (otmp == uswapwep) setuswapwep((struct obj *)0); 1342 1343 /* some things break rather than ship */ 1344 if (breaktest(otmp)) { 1345 const char *result; 1346 1347 if (objects[otmp->otyp].oc_material == GLASS 1348#ifdef TOURIST 1349 || otmp->otyp == EXPENSIVE_CAMERA 1350#endif 1351 ) { 1352 if (otmp->otyp == MIRROR) 1353 change_luck(-2); 1354 result = "crash"; 1355 } else { 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)); 1359 result = "splat"; 1360 } 1361 You_hear("a muffled %s.",result); 1362 obj_extract_self(otmp); 1363 obfree(otmp, (struct obj *) 0); 1364 return TRUE; 1365 } 1366 1367 add_to_migration(otmp); 1368 otmp->ox = cc.x; 1369 otmp->oy = cc.y; 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; 1373 1374 if(impact) { 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. 1383 */ 1384 impact_drop(otmp, x, y, 0); 1385 newsym(x,y); 1386 } 1387 return(TRUE); 1388} 1389 1390void 1391obj_delivery() 1392{ 1393 register struct obj *otmp, *otmp2; 1394 register int nx, ny; 1395 long where; 1396 1397 for (otmp = migrating_objs; otmp; otmp = otmp2) { 1398 otmp2 = otmp->nobj; 1399 if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue; 1400 1401 obj_extract_self(otmp); 1402 where = otmp->owornmask; /* destination code */ 1403 otmp->owornmask = 0L; 1404 1405 switch ((int)where) { 1406 case MIGR_STAIRS_UP: nx = xupstair, ny = yupstair; 1407 break; 1408 case MIGR_LADDER_UP: nx = xupladder, ny = yupladder; 1409 break; 1410 case MIGR_SSTAIRS: nx = sstairs.sx, ny = sstairs.sy; 1411 break; 1412 case MIGR_NEAR_PLAYER: nx = u.ux, ny = u.uy; 1413 break; 1414 default: 1415 case MIGR_RANDOM: nx = ny = 0; 1416 break; 1417 } 1418 if (nx > 0) { 1419 place_object(otmp, nx, ny); 1420 stackobj(otmp); 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; 1426 rloco(otmp); 1427 } 1428 } 1429} 1430 1431STATIC_OVL void 1432otransit_msg(otmp, nodrop, num) 1433register struct obj *otmp; 1434register boolean nodrop; 1435long num; 1436{ 1437 char obuf[BUFSZ]; 1438 1439 Sprintf(obuf, "%s%s", 1440 (otmp->otyp == CORPSE && 1441 type_is_pname(&mons[otmp->corpsenm])) ? "" : "The ", 1442 xname(otmp)); 1443 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" : ""); 1449 if(nodrop) 1450 Sprintf(eos(obuf), "."); 1451 else 1452 Sprintf(eos(obuf), " and %s %s.", 1453 otense(otmp, "fall"), gate_str); 1454 pline("%s", obuf); 1455 } else if(!nodrop) 1456 pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str); 1457} 1458 1459/* migration destination for objects which fall down to next level */ 1460schar 1461down_gate(x, y) 1462xchar x, y; 1463{ 1464 struct trap *ttmp; 1465 1466 gate_str = 0; 1467 /* this matches the player restriction in goto_level() */ 1468 if (on_level(&u.uz, &qstart_level) && !ok_to_quest()) 1469 return MIGR_NOWHERE; 1470 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; 1476 } 1477 if (xdnladder == x && ydnladder == y) { 1478 gate_str = "down the ladder"; 1479 return MIGR_LADDER_UP; 1480 } 1481 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"; 1486 return MIGR_RANDOM; 1487 } 1488 return MIGR_NOWHERE; 1489} 1490 1491/*dokick.c*/ 1492