1 /* $NetBSD: hack.apply.c,v 1.13 2011/08/07 06:03:45 dholland Exp $ */ 2 3 /* 4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica, 5 * Amsterdam 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are 10 * met: 11 * 12 * - Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * - Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * - Neither the name of the Stichting Centrum voor Wiskunde en 20 * Informatica, nor the names of its contributors may be used to endorse or 21 * promote products derived from this software without specific prior 22 * written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org> 39 * All rights reserved. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. The name of the author may not be used to endorse or promote products 50 * derived from this software without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 62 */ 63 64 #include "hack.h" 65 #include "extern.h" 66 #include "def.edog.h" 67 #include "def.mkroom.h" 68 69 static void use_camera(struct obj *); 70 static int in_ice_box(struct obj *); 71 static int ck_ice_box(struct obj *); 72 static int out_ice_box(struct obj *); 73 static void use_ice_box(struct obj *); 74 static struct monst *bchit(int, int , int , int); 75 static void use_whistle(struct obj *); 76 static void use_magic_whistle(struct obj *); 77 static int dig(void); 78 static int use_pick_axe(struct obj *); 79 80 int 81 doapply(void) 82 { 83 struct obj *obj; 84 int res = 1; 85 86 obj = getobj("(", "use or apply"); 87 if (!obj) 88 return (0); 89 90 switch (obj->otyp) { 91 case EXPENSIVE_CAMERA: 92 use_camera(obj); 93 break; 94 case ICE_BOX: 95 use_ice_box(obj); 96 break; 97 case PICK_AXE: 98 res = use_pick_axe(obj); 99 break; 100 101 case MAGIC_WHISTLE: 102 if (pl_character[0] == 'W' || u.ulevel > 9) { 103 use_magic_whistle(obj); 104 break; 105 } 106 /* FALLTHROUGH */ 107 case WHISTLE: 108 use_whistle(obj); 109 break; 110 111 case CAN_OPENER: 112 if (!carrying(TIN)) { 113 pline("You have no can to open."); 114 goto xit; 115 } 116 pline("You cannot open a tin without eating its contents."); 117 pline("In order to eat, use the 'e' command."); 118 if (obj != uwep) 119 pline("Opening the tin will be much easier if you wield the can-opener."); 120 goto xit; 121 122 default: 123 pline("Sorry, I don't know how to use that."); 124 xit: 125 nomul(0); 126 return (0); 127 } 128 nomul(0); 129 return (res); 130 } 131 132 /* ARGSUSED */ 133 static void 134 use_camera(struct obj *obj __unused) 135 { 136 struct monst *mtmp; 137 if (!getdir(1)) { /* ask: in what direction? */ 138 flags.move = multi = 0; 139 return; 140 } 141 if (u.uswallow) { 142 pline("You take a picture of %s's stomach.", monnam(u.ustuck)); 143 return; 144 } 145 if (u.dz) { 146 pline("You take a picture of the %s.", 147 (u.dz > 0) ? "floor" : "ceiling"); 148 return; 149 } 150 if ((mtmp = bchit(u.dx, u.dy, COLNO, '!')) != NULL) { 151 if (mtmp->msleep) { 152 mtmp->msleep = 0; 153 pline("The flash awakens %s.", monnam(mtmp)); /* a3 */ 154 } else if (mtmp->data->mlet != 'y') 155 if (mtmp->mcansee || mtmp->mblinded) { 156 int tmp = dist(mtmp->mx, mtmp->my); 157 int tmp2; 158 if (cansee(mtmp->mx, mtmp->my)) 159 pline("%s is blinded by the flash!", Monnam(mtmp)); 160 setmangry(mtmp); 161 if (tmp < 9 && !mtmp->isshk && rn2(4)) { 162 mtmp->mflee = 1; 163 if (rn2(4)) 164 mtmp->mfleetim = rnd(100); 165 } 166 if (tmp < 3) 167 mtmp->mcansee = mtmp->mblinded = 0; 168 else { 169 tmp2 = mtmp->mblinded; 170 tmp2 += rnd(1 + 50 / tmp); 171 if (tmp2 > 127) 172 tmp2 = 127; 173 mtmp->mblinded = tmp2; 174 mtmp->mcansee = 0; 175 } 176 } 177 } 178 } 179 180 static 181 struct obj *current_ice_box;/* a local variable of use_ice_box, to be 182 * used by its local procedures in/ck_ice_box */ 183 static int 184 in_ice_box(struct obj *obj) 185 { 186 if (obj == current_ice_box || 187 (Punished && (obj == uball || obj == uchain))) { 188 pline("You must be kidding."); 189 return (0); 190 } 191 if (obj->owornmask & (W_ARMOR | W_RING)) { 192 pline("You cannot refrigerate something you are wearing."); 193 return (0); 194 } 195 if (obj->owt + current_ice_box->owt > 70) { 196 pline("It won't fit."); 197 return (1); /* be careful! */ 198 } 199 if (obj == uwep) { 200 if (uwep->cursed) { 201 pline("Your weapon is welded to your hand!"); 202 return (0); 203 } 204 setuwep((struct obj *) 0); 205 } 206 current_ice_box->owt += obj->owt; 207 freeinv(obj); 208 obj->o_cnt_id = current_ice_box->o_id; 209 obj->nobj = fcobj; 210 fcobj = obj; 211 obj->age = moves - obj->age; /* actual age */ 212 return (1); 213 } 214 215 static int 216 ck_ice_box(struct obj *obj) 217 { 218 return (obj->o_cnt_id == current_ice_box->o_id); 219 } 220 221 static int 222 out_ice_box(struct obj *obj) 223 { 224 struct obj *otmp; 225 if (obj == fcobj) 226 fcobj = fcobj->nobj; 227 else { 228 for (otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj) 229 if (!otmp->nobj) 230 panic("out_ice_box"); 231 otmp->nobj = obj->nobj; 232 } 233 current_ice_box->owt -= obj->owt; 234 obj->age = moves - obj->age; /* simulated point of time */ 235 (void) addinv(obj); 236 return 0; 237 } 238 239 static void 240 use_ice_box(struct obj *obj) 241 { 242 int cnt = 0; 243 struct obj *otmp; 244 current_ice_box = obj; /* for use by in/out_ice_box */ 245 for (otmp = fcobj; otmp; otmp = otmp->nobj) 246 if (otmp->o_cnt_id == obj->o_id) 247 cnt++; 248 if (!cnt) 249 pline("Your ice-box is empty."); 250 else { 251 pline("Do you want to take something out of the ice-box? [yn] "); 252 if (readchar() == 'y') 253 if (askchain(fcobj, NULL, 0, out_ice_box, ck_ice_box, 0)) 254 return; 255 pline("That was all. Do you wish to put something in? [yn] "); 256 if (readchar() != 'y') 257 return; 258 } 259 /* call getobj: 0: allow cnt; #: allow all types; %: expect food */ 260 otmp = getobj("0#%", "put in"); 261 if (!otmp || !in_ice_box(otmp)) 262 flags.move = multi = 0; 263 } 264 265 static struct monst * 266 bchit(int ddx, int ddy, int range, int sym) 267 { 268 struct monst *mtmp = (struct monst *) 0; 269 int bchx = u.ux, bchy = u.uy; 270 271 if (sym) 272 Tmp_at(-1, sym);/* open call */ 273 while (range--) { 274 bchx += ddx; 275 bchy += ddy; 276 if ((mtmp = m_at(bchx, bchy)) != NULL) 277 break; 278 if (!ZAP_POS(levl[bchx][bchy].typ)) { 279 bchx -= ddx; 280 bchy -= ddy; 281 break; 282 } 283 if (sym) 284 Tmp_at(bchx, bchy); 285 } 286 if (sym) 287 Tmp_at(-1, -1); 288 return (mtmp); 289 } 290 291 /* ARGSUSED */ 292 static void 293 use_whistle(struct obj *obj __unused) 294 { 295 struct monst *mtmp = fmon; 296 pline("You produce a high whistling sound."); 297 while (mtmp) { 298 if (dist(mtmp->mx, mtmp->my) < u.ulevel * 20) { 299 if (mtmp->msleep) 300 mtmp->msleep = 0; 301 if (mtmp->mtame) 302 EDOG(mtmp)->whistletime = moves; 303 } 304 mtmp = mtmp->nmon; 305 } 306 } 307 308 /* ARGSUSED */ 309 static void 310 use_magic_whistle(struct obj *obj __unused) 311 { 312 struct monst *mtmp = fmon; 313 pline("You produce a strange whistling sound."); 314 while (mtmp) { 315 if (mtmp->mtame) 316 mnexto(mtmp); 317 mtmp = mtmp->nmon; 318 } 319 } 320 321 static int dig_effort; /* effort expended on current pos */ 322 static uchar dig_level; 323 static coord dig_pos; 324 static boolean dig_down; 325 326 static int 327 dig(void) 328 { 329 struct rm *lev; 330 int dpx = dig_pos.x, dpy = dig_pos.y; 331 332 /* perhaps a nymph stole his pick-axe while he was busy digging */ 333 /* or perhaps he teleported away */ 334 if (u.uswallow || !uwep || uwep->otyp != PICK_AXE || 335 dig_level != dlevel || 336 ((dig_down && (dpx != u.ux || dpy != u.uy)) || 337 (!dig_down && dist(dpx, dpy) > 2))) 338 return (0); 339 340 dig_effort += 10 + abon() + uwep->spe + rn2(5); 341 if (dig_down) { 342 if (!xdnstair) { 343 pline("The floor here seems too hard to dig in."); 344 return (0); 345 } 346 if (dig_effort > 250) { 347 dighole(); 348 return (0); /* done with digging */ 349 } 350 if (dig_effort > 50) { 351 struct trap *ttmp = t_at(dpx, dpy); 352 353 if (!ttmp) { 354 ttmp = maketrap(dpx, dpy, PIT); 355 ttmp->tseen = 1; 356 pline("You have dug a pit."); 357 u.utrap = rn1(4, 2); 358 u.utraptype = TT_PIT; 359 return (0); 360 } 361 } 362 } else if (dig_effort > 100) { 363 const char *digtxt; 364 struct obj *obj; 365 366 lev = &levl[dpx][dpy]; 367 if ((obj = sobj_at(ENORMOUS_ROCK, dpx, dpy)) != NULL) { 368 fracture_rock(obj); 369 digtxt = "The rock falls apart."; 370 } else if (!lev->typ || lev->typ == SCORR) { 371 lev->typ = CORR; 372 digtxt = "You succeeded in cutting away some rock."; 373 } else if (lev->typ == HWALL || lev->typ == VWALL 374 || lev->typ == SDOOR) { 375 lev->typ = xdnstair ? DOOR : ROOM; 376 digtxt = "You just made an opening in the wall."; 377 } else 378 digtxt = "Now what exactly was it that you were digging in?"; 379 mnewsym(dpx, dpy); 380 prl(dpx, dpy); 381 pline("%s", digtxt); /* after mnewsym & prl */ 382 return (0); 383 } else { 384 if (IS_WALL(levl[dpx][dpy].typ)) { 385 int rno = inroom(dpx, dpy); 386 387 if (rno >= 0 && rooms[rno].rtype >= 8) { 388 pline("This wall seems too hard to dig into."); 389 return (0); 390 } 391 } 392 pline("You hit the rock with all your might."); 393 } 394 return (1); 395 } 396 397 /* When will hole be finished? Very rough indication used by shopkeeper. */ 398 int 399 holetime(void) 400 { 401 return ((occupation == dig) ? (250 - dig_effort) / 20 : -1); 402 } 403 404 void 405 dighole(void) 406 { 407 struct trap *ttmp = t_at(u.ux, u.uy); 408 409 if (!xdnstair) { 410 pline("The floor here seems too hard to dig in."); 411 } else { 412 if (ttmp) 413 ttmp->ttyp = TRAPDOOR; 414 else 415 ttmp = maketrap(u.ux, u.uy, TRAPDOOR); 416 ttmp->tseen = 1; 417 pline("You've made a hole in the floor."); 418 if (!u.ustuck) { 419 if (inshop()) 420 shopdig(1); 421 pline("You fall through ..."); 422 if (u.utraptype == TT_PIT) { 423 u.utrap = 0; 424 u.utraptype = 0; 425 } 426 goto_level(dlevel + 1, FALSE); 427 } 428 } 429 } 430 431 static int 432 use_pick_axe(struct obj *obj) 433 { 434 char dirsyms[12]; 435 char *dsp = dirsyms, *sdp = sdir; 436 struct monst *mtmp; 437 struct rm *lev; 438 int rx, ry, res = 0; 439 440 if (obj != uwep) { 441 if (uwep && uwep->cursed) { 442 /* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */ 443 pline("Since your weapon is welded to your hand,"); 444 pline("you cannot use that pick-axe."); 445 return (0); 446 } 447 pline("You now wield %s.", doname(obj)); 448 setuwep(obj); 449 res = 1; 450 } 451 while (*sdp) { 452 (void) movecmd(*sdp); /* sets u.dx and u.dy and u.dz */ 453 rx = u.ux + u.dx; 454 ry = u.uy + u.dy; 455 if (u.dz > 0 || (u.dz == 0 && isok(rx, ry) && 456 (IS_ROCK(levl[rx][ry].typ) 457 || sobj_at(ENORMOUS_ROCK, rx, ry)))) 458 *dsp++ = *sdp; 459 sdp++; 460 } 461 *dsp = 0; 462 pline("In what direction do you want to dig? [%s] ", dirsyms); 463 if (!getdir(0)) /* no txt */ 464 return (res); 465 if (u.uswallow && attack(u.ustuck)) /* return(1) */ 466 ; 467 else if (u.dz < 0) 468 pline("You cannot reach the ceiling."); 469 else if (u.dz == 0) { 470 if (Confusion) 471 confdir(); 472 rx = u.ux + u.dx; 473 ry = u.uy + u.dy; 474 if ((mtmp = m_at(rx, ry)) && attack(mtmp)) 475 return (1); 476 if (!isok(rx, ry)) { 477 pline("Clash!"); 478 return (1); 479 } 480 lev = &levl[rx][ry]; 481 if (lev->typ == DOOR) 482 pline("Your %s against the door.", 483 aobjnam(obj, "clang")); 484 else if (!IS_ROCK(lev->typ) 485 && !sobj_at(ENORMOUS_ROCK, rx, ry)) { 486 /* ACCESSIBLE or POOL */ 487 pline("You swing your %s through thin air.", 488 aobjnam(obj, NULL)); 489 } else { 490 if (dig_pos.x != rx || dig_pos.y != ry 491 || dig_level != dlevel || dig_down) { 492 dig_down = FALSE; 493 dig_pos.x = rx; 494 dig_pos.y = ry; 495 dig_level = dlevel; 496 dig_effort = 0; 497 pline("You start digging."); 498 } else 499 pline("You continue digging."); 500 occupation = dig; 501 occtxt = "digging"; 502 } 503 } else if (Levitation) { 504 pline("You cannot reach the floor."); 505 } else { 506 if (dig_pos.x != u.ux || dig_pos.y != u.uy 507 || dig_level != dlevel || !dig_down) { 508 dig_down = TRUE; 509 dig_pos.x = u.ux; 510 dig_pos.y = u.uy; 511 dig_level = dlevel; 512 dig_effort = 0; 513 pline("You start digging in the floor."); 514 if (inshop()) 515 shopdig(0); 516 } else 517 pline("You continue digging in the floor."); 518 occupation = dig; 519 occtxt = "digging"; 520 } 521 return (1); 522 } 523