1 /* $OpenBSD: hack.apply.c,v 1.5 2009/10/27 23:59:25 deraadt 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 "def.edog.h" 66 extern int (*occupation)(void); 67 extern char *occtxt; 68 extern char quitchars[]; 69 extern char pl_character[]; 70 71 static void use_camera(struct obj *); 72 static void use_ice_box(struct obj *); 73 int in_ice_box(struct obj *); 74 int ck_ice_box(struct obj *); 75 int out_ice_box(struct obj *); 76 static struct monst *bchit(int, int, int, char); 77 static void use_whistle(struct obj *); 78 static void use_magic_whistle(struct obj *); 79 static int dig(void); 80 static int use_pick_axe(struct obj *); 81 82 int 83 doapply() 84 { 85 struct obj *obj; 86 int res = 1; 87 88 obj = getobj("(", "use or apply"); 89 if(!obj) return(0); 90 91 switch(obj->otyp){ 92 case EXPENSIVE_CAMERA: 93 use_camera(obj); break; 94 case ICE_BOX: 95 use_ice_box(obj); break; 96 case PICK_AXE: 97 res = use_pick_axe(obj); 98 break; 99 100 case MAGIC_WHISTLE: 101 if(pl_character[0] == 'W' || u.ulevel > 9) { 102 use_magic_whistle(obj); 103 break; 104 } 105 /* fall into next case */ 106 case WHISTLE: 107 use_whistle(obj); 108 break; 109 110 case CAN_OPENER: 111 if(!carrying(TIN)) { 112 pline("You have no can to open."); 113 goto xit; 114 } 115 pline("You cannot open a tin without eating its contents."); 116 pline("In order to eat, use the 'e' command."); 117 if(obj != uwep) 118 pline("Opening the tin will be much easier if you wield the can-opener."); 119 goto xit; 120 121 default: 122 pline("Sorry, I don't know how to use that."); 123 xit: 124 nomul(0); 125 return(0); 126 } 127 nomul(0); 128 return(res); 129 } 130 131 /* ARGSUSED */ 132 static void 133 use_camera(struct obj *obj) 134 { 135 struct monst *mtmp; 136 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, '!'))) { 151 if(mtmp->msleep){ 152 mtmp->msleep = 0; 153 pline("The flash awakens %s.", monnam(mtmp)); /* a3 */ 154 } else 155 if(mtmp->data->mlet != 'y') 156 if(mtmp->mcansee || mtmp->mblinded){ 157 int tmp = dist(mtmp->mx,mtmp->my); 158 int tmp2; 159 if(cansee(mtmp->mx,mtmp->my)) 160 pline("%s is blinded by the flash!", Monnam(mtmp)); 161 setmangry(mtmp); 162 if(tmp < 9 && !mtmp->isshk && rn2(4)) { 163 mtmp->mflee = 1; 164 if(rn2(4)) mtmp->mfleetim = rnd(100); 165 } 166 if(tmp < 3) mtmp->mcansee = mtmp->mblinded = 0; 167 else { 168 tmp2 = mtmp->mblinded; 169 tmp2 += rnd(1 + 50/tmp); 170 if(tmp2 > 127) tmp2 = 127; 171 mtmp->mblinded = tmp2; 172 mtmp->mcansee = 0; 173 } 174 } 175 } 176 } 177 178 static 179 struct obj *current_ice_box; /* a local variable of use_ice_box, to be 180 used by its local procedures in/ck_ice_box */ 181 int 182 in_ice_box(struct obj *obj) 183 { 184 if(obj == current_ice_box || 185 (Punished && (obj == uball || obj == uchain))){ 186 pline("You must be kidding."); 187 return(0); 188 } 189 if(obj->owornmask & (W_ARMOR | W_RING)) { 190 pline("You cannot refrigerate something you are wearing."); 191 return(0); 192 } 193 if(obj->owt + current_ice_box->owt > 70) { 194 pline("It won't fit."); 195 return(1); /* be careful! */ 196 } 197 if(obj == uwep) { 198 if(uwep->cursed) { 199 pline("Your weapon is welded to your hand!"); 200 return(0); 201 } 202 setuwep((struct obj *) 0); 203 } 204 current_ice_box->owt += obj->owt; 205 freeinv(obj); 206 obj->o_cnt_id = current_ice_box->o_id; 207 obj->nobj = fcobj; 208 fcobj = obj; 209 obj->age = moves - obj->age; /* actual age */ 210 return(1); 211 } 212 213 int 214 ck_ice_box(struct obj *obj) 215 { 216 return(obj->o_cnt_id == current_ice_box->o_id); 217 } 218 219 int 220 out_ice_box(struct obj *obj) 221 { 222 struct obj *otmp; 223 224 if (obj == fcobj) 225 fcobj = fcobj->nobj; 226 else { 227 for(otmp = fcobj; otmp->nobj != obj; otmp = otmp->nobj) 228 if(!otmp->nobj) panic("out_ice_box"); 229 otmp->nobj = obj->nobj; 230 } 231 current_ice_box->owt -= obj->owt; 232 obj->age = moves - obj->age; /* simulated point of time */ 233 (void) addinv(obj); 234 return(0); 235 } 236 237 static void 238 use_ice_box(struct obj *obj) 239 { 240 int cnt = 0; 241 struct obj *otmp; 242 current_ice_box = obj; /* for use by in/out_ice_box */ 243 for(otmp = fcobj; otmp; otmp = otmp->nobj) 244 if(otmp->o_cnt_id == obj->o_id) 245 cnt++; 246 if(!cnt) pline("Your ice-box is empty."); 247 else { 248 pline("Do you want to take something out of the ice-box? [yn] "); 249 if(readchar() == 'y') 250 if(askchain(fcobj, NULL, 0, out_ice_box, ck_ice_box, 0)) 251 return; 252 pline("That was all. Do you wish to put something in? [yn] "); 253 if(readchar() != 'y') return; 254 } 255 /* call getobj: 0: allow cnt; #: allow all types; %: expect food */ 256 otmp = getobj("0#%", "put in"); 257 if(!otmp || !in_ice_box(otmp)) 258 flags.move = multi = 0; 259 } 260 261 static 262 struct monst * 263 bchit(int ddx, int ddy, int range, char sym) 264 { 265 struct monst *mtmp = (struct monst *) 0; 266 int bchx = u.ux, bchy = u.uy; 267 268 if(sym) Tmp_at(-1, sym); /* open call */ 269 while(range--) { 270 bchx += ddx; 271 bchy += ddy; 272 if ((mtmp = m_at(bchx,bchy))) 273 break; 274 if(!ZAP_POS(levl[bchx][bchy].typ)) { 275 bchx -= ddx; 276 bchy -= ddy; 277 break; 278 } 279 if(sym) 280 Tmp_at(bchx, bchy); 281 } 282 if(sym) 283 Tmp_at(-1, -1); 284 return(mtmp); 285 } 286 287 /* ARGSUSED */ 288 static void 289 use_whistle(struct obj *obj) 290 { 291 struct monst *mtmp = fmon; 292 pline("You produce a high whistling sound."); 293 while(mtmp) { 294 if(dist(mtmp->mx,mtmp->my) < u.ulevel*20) { 295 if(mtmp->msleep) 296 mtmp->msleep = 0; 297 if(mtmp->mtame) 298 EDOG(mtmp)->whistletime = moves; 299 } 300 mtmp = mtmp->nmon; 301 } 302 } 303 304 /* ARGSUSED */ 305 static void 306 use_magic_whistle(struct obj *obj) 307 { 308 struct monst *mtmp = fmon; 309 pline("You produce a strange whistling sound."); 310 while(mtmp) { 311 if(mtmp->mtame) mnexto(mtmp); 312 mtmp = mtmp->nmon; 313 } 314 } 315 316 static int dig_effort; /* effort expended on current pos */ 317 static uchar dig_level; 318 static coord dig_pos; 319 static boolean dig_down; 320 321 static int 322 dig() 323 { 324 struct rm *lev; 325 int dpx = dig_pos.x, dpy = dig_pos.y; 326 327 /* perhaps a nymph stole his pick-axe while he was busy digging */ 328 /* or perhaps he teleported away */ 329 if(u.uswallow || !uwep || uwep->otyp != PICK_AXE || 330 dig_level != dlevel || 331 ((dig_down && (dpx != u.ux || dpy != u.uy)) || 332 (!dig_down && dist(dpx,dpy) > 2))) 333 return(0); 334 335 dig_effort += 10 + abon() + uwep->spe + rn2(5); 336 if(dig_down) { 337 if(!xdnstair) { 338 pline("The floor here seems too hard to dig in."); 339 return(0); 340 } 341 if(dig_effort > 250) { 342 dighole(); 343 return(0); /* done with digging */ 344 } 345 if(dig_effort > 50) { 346 struct trap *ttmp = t_at(dpx,dpy); 347 348 if(!ttmp) { 349 ttmp = maketrap(dpx,dpy,PIT); 350 ttmp->tseen = 1; 351 pline("You have dug a pit."); 352 u.utrap = rn1(4,2); 353 u.utraptype = TT_PIT; 354 return(0); 355 } 356 } 357 } else 358 if (dig_effort > 100) { 359 char *digtxt; 360 struct obj *obj; 361 362 lev = &levl[dpx][dpy]; 363 if ((obj = sobj_at(ENORMOUS_ROCK, dpx, dpy))) { 364 fracture_rock(obj); 365 digtxt = "The rock falls apart."; 366 } else if(!lev->typ || lev->typ == SCORR) { 367 lev->typ = CORR; 368 digtxt = "You succeeded in cutting away some rock."; 369 } else if(lev->typ == HWALL || lev->typ == VWALL 370 || lev->typ == SDOOR) { 371 lev->typ = xdnstair ? DOOR : ROOM; 372 digtxt = "You just made an opening in the wall."; 373 } else 374 digtxt = "Now what exactly was it that you were digging in?"; 375 mnewsym(dpx, dpy); 376 prl(dpx, dpy); 377 pline(digtxt); /* after mnewsym & prl */ 378 return(0); 379 } else { 380 if(IS_WALL(levl[dpx][dpy].typ)) { 381 int rno = inroom(dpx,dpy); 382 383 if(rno >= 0 && rooms[rno].rtype >= 8) { 384 pline("This wall seems too hard to dig into."); 385 return(0); 386 } 387 } 388 pline("You hit the rock with all your might."); 389 } 390 return(1); 391 } 392 393 /* When will hole be finished? Very rough indication used by shopkeeper. */ 394 int 395 holetime() 396 { 397 return( (occupation == dig) ? (250 - dig_effort)/20 : -1); 398 } 399 400 void 401 dighole() 402 { 403 struct trap *ttmp = t_at(u.ux, u.uy); 404 405 if(!xdnstair) { 406 pline("The floor here seems too hard to dig in."); 407 } else { 408 if(ttmp) 409 ttmp->ttyp = TRAPDOOR; 410 else 411 ttmp = maketrap(u.ux, u.uy, TRAPDOOR); 412 ttmp->tseen = 1; 413 pline("You've made a hole in the floor."); 414 if(!u.ustuck) { 415 if(inshop()) 416 shopdig(1); 417 pline("You fall through ..."); 418 if(u.utraptype == TT_PIT) { 419 u.utrap = 0; 420 u.utraptype = 0; 421 } 422 goto_level(dlevel+1, FALSE); 423 } 424 } 425 } 426 427 static int 428 use_pick_axe(struct obj *obj) 429 { 430 char dirsyms[12]; 431 extern char sdir[]; 432 char *dsp = dirsyms, *sdp = sdir; 433 struct monst *mtmp; 434 struct rm *lev; 435 int rx, ry, res = 0; 436 437 if(obj != uwep) { 438 if(uwep && uwep->cursed) { 439 /* Andreas Bormann - ihnp4!decvax!mcvax!unido!ab */ 440 pline("Since your weapon is welded to your hand,"); 441 pline("you cannot use that pick-axe."); 442 return(0); 443 } 444 pline("You now wield %s.", doname(obj)); 445 setuwep(obj); 446 res = 1; 447 } 448 while(*sdp) { 449 (void) movecmd(*sdp); /* sets u.dx and u.dy and u.dz */ 450 rx = u.ux + u.dx; 451 ry = u.uy + u.dy; 452 if(u.dz > 0 || (u.dz == 0 && isok(rx, ry) && 453 (IS_ROCK(levl[rx][ry].typ) 454 || sobj_at(ENORMOUS_ROCK, rx, ry)))) 455 *dsp++ = *sdp; 456 sdp++; 457 } 458 *dsp = 0; 459 pline("In what direction do you want to dig? [%s] ", dirsyms); 460 if(!getdir(0)) /* no txt */ 461 return(res); 462 if(u.uswallow && attack(u.ustuck)) /* return(1) */; 463 else 464 if(u.dz < 0) 465 pline("You cannot reach the ceiling."); 466 else 467 if(u.dz == 0) { 468 if(Confusion) 469 confdir(); 470 rx = u.ux + u.dx; 471 ry = u.uy + u.dy; 472 if((mtmp = m_at(rx, ry)) && attack(mtmp)) 473 return(1); 474 if(!isok(rx, ry)) { 475 pline("Clash!"); 476 return(1); 477 } 478 lev = &levl[rx][ry]; 479 if(lev->typ == DOOR) 480 pline("Your %s against the door.", 481 aobjnam(obj, "clang")); 482 else if(!IS_ROCK(lev->typ) 483 && !sobj_at(ENORMOUS_ROCK, rx, ry)) { 484 /* ACCESSIBLE or POOL */ 485 pline("You swing your %s through thin air.", 486 aobjnam(obj, (char *) 0)); 487 } else { 488 if(dig_pos.x != rx || dig_pos.y != ry 489 || dig_level != dlevel || dig_down) { 490 dig_down = FALSE; 491 dig_pos.x = rx; 492 dig_pos.y = ry; 493 dig_level = dlevel; 494 dig_effort = 0; 495 pline("You start digging."); 496 } else 497 pline("You continue digging."); 498 occupation = dig; 499 occtxt = "digging"; 500 } 501 } else if(Levitation) { 502 pline("You cannot reach the floor."); 503 } else { 504 if(dig_pos.x != u.ux || dig_pos.y != u.uy 505 || dig_level != dlevel || !dig_down) { 506 dig_down = TRUE; 507 dig_pos.x = u.ux; 508 dig_pos.y = u.uy; 509 dig_level = dlevel; 510 dig_effort = 0; 511 pline("You start digging in the floor."); 512 if(inshop()) 513 shopdig(0); 514 } else 515 pline("You continue digging in the floor."); 516 occupation = dig; 517 occtxt = "digging"; 518 } 519 return(1); 520 } 521