1 /* $OpenBSD: hack.do.c,v 1.6 2003/05/19 06:30:56 pjanzen 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 #ifndef lint 65 static const char rcsid[] = "$OpenBSD: hack.do.c,v 1.6 2003/05/19 06:30:56 pjanzen Exp $"; 66 #endif /* not lint */ 67 68 /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) and 't' (throw) */ 69 70 #include <stdlib.h> 71 #include <unistd.h> 72 #include "hack.h" 73 74 extern boolean level_exists[]; 75 extern struct monst youmonst; 76 extern char *nomovemsg; 77 78 static int drop(struct obj *); 79 80 int 81 dodrop() 82 { 83 return(drop(getobj("0$#", "drop"))); 84 } 85 86 static int 87 drop(struct obj *obj) 88 { 89 if(!obj) return(0); 90 if(obj->olet == '$') { /* pseudo object */ 91 long amount = OGOLD(obj); 92 93 if(amount == 0) 94 pline("You didn't drop any gold pieces."); 95 else { 96 mkgold(amount, u.ux, u.uy); 97 pline("You dropped %ld gold piece%s.", 98 amount, plur(amount)); 99 if(Invisible) newsym(u.ux, u.uy); 100 } 101 free((char *) obj); 102 return(1); 103 } 104 if(obj->owornmask & (W_ARMOR | W_RING)){ 105 pline("You cannot drop something you are wearing."); 106 return(0); 107 } 108 if(obj == uwep) { 109 if(uwep->cursed) { 110 pline("Your weapon is welded to your hand!"); 111 return(0); 112 } 113 setuwep((struct obj *) 0); 114 } 115 pline("You dropped %s.", doname(obj)); 116 dropx(obj); 117 return(1); 118 } 119 120 /* Called in several places - should not produce texts */ 121 void 122 dropx(struct obj *obj) 123 { 124 freeinv(obj); 125 dropy(obj); 126 } 127 128 void 129 dropy(struct obj *obj) 130 { 131 if(obj->otyp == CRYSKNIFE) 132 obj->otyp = WORM_TOOTH; 133 obj->ox = u.ux; 134 obj->oy = u.uy; 135 obj->nobj = fobj; 136 fobj = obj; 137 if(Invisible) newsym(u.ux,u.uy); 138 subfrombill(obj); 139 stackobj(obj); 140 } 141 142 /* drop several things */ 143 int 144 doddrop() 145 { 146 return(ggetobj("drop", drop, 0)); 147 } 148 149 int 150 dodown() 151 { 152 if(u.ux != xdnstair || u.uy != ydnstair) { 153 pline("You can't go down here."); 154 return(0); 155 } 156 if(u.ustuck) { 157 pline("You are being held, and cannot go down."); 158 return(1); 159 } 160 if(Levitation) { 161 pline("You're floating high above the stairs."); 162 return(0); 163 } 164 165 goto_level(dlevel+1, TRUE); 166 return(1); 167 } 168 169 int 170 doup() 171 { 172 if(u.ux != xupstair || u.uy != yupstair) { 173 pline("You can't go up here."); 174 return(0); 175 } 176 if(u.ustuck) { 177 pline("You are being held, and cannot go up."); 178 return(1); 179 } 180 if(!Levitation && inv_weight() + 5 > 0) { 181 pline("Your load is too heavy to climb the stairs."); 182 return(1); 183 } 184 185 goto_level(dlevel-1, TRUE); 186 return(1); 187 } 188 189 void 190 goto_level(int newlevel, boolean at_stairs) 191 { 192 int fd; 193 boolean up = (newlevel < dlevel); 194 195 if(newlevel <= 0) done("escaped"); /* in fact < 0 is impossible */ 196 if(newlevel > MAXLEVEL) newlevel = MAXLEVEL; /* strange ... */ 197 if(newlevel == dlevel) return; /* this can happen */ 198 199 glo(dlevel); 200 fd = creat(lock, FMASK); 201 if(fd < 0) { 202 /* 203 * This is not quite impossible: e.g., we may have 204 * exceeded our quota. If that is the case then we 205 * cannot leave this level, and cannot save either. 206 * Another possibility is that the directory was not 207 * writable. 208 */ 209 pline("A mysterious force prevents you from going %s.", 210 up ? "up" : "down"); 211 return; 212 } 213 214 if(Punished) unplacebc(); 215 u.utrap = 0; /* needed in level_tele */ 216 u.ustuck = 0; /* idem */ 217 keepdogs(); 218 seeoff(1); 219 if(u.uswallow) /* idem */ 220 u.uswldtim = u.uswallow = 0; 221 flags.nscrinh = 1; 222 u.ux = FAR; /* hack */ 223 (void) inshop(); /* probably was a trapdoor */ 224 225 savelev(fd,dlevel); 226 (void) close(fd); 227 228 dlevel = newlevel; 229 if(maxdlevel < dlevel) 230 maxdlevel = dlevel; 231 glo(dlevel); 232 233 if(!level_exists[(int)dlevel]) 234 mklev(); 235 else { 236 extern int hackpid; 237 238 if((fd = open(lock, O_RDONLY)) < 0) { 239 pline("Cannot open %s .", lock); 240 pline("Probably someone removed it."); 241 done("tricked"); 242 } 243 getlev(fd, hackpid, dlevel); 244 (void) close(fd); 245 } 246 247 if(at_stairs) { 248 if(up) { 249 u.ux = xdnstair; 250 u.uy = ydnstair; 251 if(!u.ux) { /* entering a maze from below? */ 252 u.ux = xupstair; /* this will confuse the player! */ 253 u.uy = yupstair; 254 } 255 if(Punished && !Levitation){ 256 pline("With great effort you climb the stairs."); 257 placebc(1); 258 } 259 } else { 260 u.ux = xupstair; 261 u.uy = yupstair; 262 if(inv_weight() + 5 > 0 || Punished){ 263 pline("You fall down the stairs."); /* %% */ 264 losehp(rnd(3), "fall"); 265 if(Punished) { 266 if(uwep != uball && rn2(3)){ 267 pline("... and are hit by the iron ball."); 268 losehp(rnd(20), "iron ball"); 269 } 270 placebc(1); 271 } 272 selftouch("Falling, you"); 273 } 274 } 275 { struct monst *mtmp = m_at(u.ux, u.uy); 276 if(mtmp) 277 mnexto(mtmp); 278 } 279 } else { /* trapdoor or level_tele */ 280 do { 281 u.ux = rnd(COLNO-1); 282 u.uy = rn2(ROWNO); 283 } while(levl[(int)u.ux][(int)u.uy].typ != ROOM || 284 m_at(u.ux,u.uy)); 285 if(Punished){ 286 if(uwep != uball && !up /* %% */ && rn2(5)){ 287 pline("The iron ball falls on your head."); 288 losehp(rnd(25), "iron ball"); 289 } 290 placebc(1); 291 } 292 selftouch("Falling, you"); 293 } 294 (void) inshop(); 295 initrack(); 296 297 losedogs(); 298 { struct monst *mtmp; 299 if ((mtmp = m_at(u.ux, u.uy))) 300 mnexto(mtmp); /* riv05!a3 */ 301 } 302 flags.nscrinh = 0; 303 setsee(); 304 seeobjs(); /* make old cadavers disappear - riv05!a3 */ 305 docrt(); 306 pickup(1); 307 read_engr_at(u.ux,u.uy); 308 } 309 310 int 311 donull() 312 { 313 return(1); /* Do nothing, but let other things happen */ 314 } 315 316 int 317 dopray() 318 { 319 nomovemsg = "You finished your prayer."; 320 nomul(-3); 321 return(1); 322 } 323 324 int 325 dothrow() 326 { 327 struct obj *obj; 328 struct monst *mon; 329 int tmp; 330 331 obj = getobj("#)", "throw"); /* it is also possible to throw food */ 332 /* (or jewels, or iron balls ... ) */ 333 if(!obj || !getdir(1)) /* ask "in what direction?" */ 334 return(0); 335 if(obj->owornmask & (W_ARMOR | W_RING)){ 336 pline("You can't throw something you are wearing."); 337 return(0); 338 } 339 340 u_wipe_engr(2); 341 342 if(obj == uwep){ 343 if(obj->cursed){ 344 pline("Your weapon is welded to your hand."); 345 return(1); 346 } 347 if(obj->quan > 1) 348 setuwep(splitobj(obj, 1)); 349 else 350 setuwep((struct obj *) 0); 351 } 352 else if(obj->quan > 1) 353 (void) splitobj(obj, 1); 354 freeinv(obj); 355 if(u.uswallow) { 356 mon = u.ustuck; 357 bhitpos.x = mon->mx; 358 bhitpos.y = mon->my; 359 } else if(u.dz) { 360 if(u.dz < 0) { 361 pline("%s hits the ceiling, then falls back on top of your head.", 362 Doname(obj)); /* note: obj->quan == 1 */ 363 if(obj->olet == POTION_SYM) 364 potionhit(&youmonst, obj); 365 else { 366 if(uarmh) pline("Fortunately, you are wearing a helmet!"); 367 losehp(uarmh ? 1 : rnd((int)(obj->owt)), "falling object"); 368 dropy(obj); 369 } 370 } else { 371 pline("%s hits the floor.", Doname(obj)); 372 if(obj->otyp == EXPENSIVE_CAMERA) { 373 pline("It is shattered in a thousand pieces!"); 374 obfree(obj, Null(obj)); 375 } else if(obj->otyp == EGG) { 376 pline("\"Splash!\""); 377 obfree(obj, Null(obj)); 378 } else if(obj->olet == POTION_SYM) { 379 pline("The flask breaks, and you smell a peculiar odor ..."); 380 potionbreathe(obj); 381 obfree(obj, Null(obj)); 382 } else { 383 dropy(obj); 384 } 385 } 386 return(1); 387 } else if(obj->otyp == BOOMERANG) { 388 mon = boomhit(u.dx, u.dy); 389 if(mon == &youmonst) { /* the thing was caught */ 390 (void) addinv(obj); 391 return(1); 392 } 393 } else { 394 if(obj->otyp == PICK_AXE && shkcatch(obj)) 395 return(1); 396 397 mon = bhit(u.dx, u.dy, (obj->otyp == ICE_BOX) ? 1 : 398 (!Punished || obj != uball) ? 8 : !u.ustuck ? 5 : 1, 399 obj->olet, NULL, NULL, obj); 400 } 401 if(mon) { 402 /* awake monster if sleeping */ 403 wakeup(mon); 404 405 if(obj->olet == WEAPON_SYM) { 406 tmp = -1+u.ulevel+mon->data->ac+abon(); 407 if(obj->otyp < ROCK) { 408 if(!uwep || 409 uwep->otyp != obj->otyp+(BOW-ARROW)) 410 tmp -= 4; 411 else { 412 tmp += uwep->spe; 413 } 414 } else 415 if(obj->otyp == BOOMERANG) tmp += 4; 416 tmp += obj->spe; 417 if(u.uswallow || tmp >= rnd(20)) { 418 if(hmon(mon,obj,1) == TRUE){ 419 /* mon still alive */ 420 #ifndef NOWORM 421 cutworm(mon,bhitpos.x,bhitpos.y,obj->otyp); 422 #endif /* NOWORM */ 423 } else mon = 0; 424 /* weapons thrown disappear sometimes */ 425 if(obj->otyp < BOOMERANG && rn2(3)) { 426 /* check bill; free */ 427 obfree(obj, (struct obj *) 0); 428 return(1); 429 } 430 } else miss(objects[obj->otyp].oc_name, mon); 431 } else if(obj->otyp == HEAVY_IRON_BALL) { 432 tmp = -1+u.ulevel+mon->data->ac+abon(); 433 if(!Punished || obj != uball) tmp += 2; 434 if(u.utrap) tmp -= 2; 435 if(u.uswallow || tmp >= rnd(20)) { 436 if(hmon(mon,obj,1) == FALSE) 437 mon = 0; /* he died */ 438 } else miss("iron ball", mon); 439 } else if(obj->olet == POTION_SYM && u.ulevel > rn2(15)) { 440 potionhit(mon, obj); 441 return(1); 442 } else { 443 if(cansee(bhitpos.x,bhitpos.y)) 444 pline("You miss %s.",monnam(mon)); 445 else pline("You miss it."); 446 if(obj->olet == FOOD_SYM && mon->data->mlet == 'd') 447 if(tamedog(mon,obj)) return(1); 448 if(obj->olet == GEM_SYM && mon->data->mlet == 'u' && 449 !mon->mtame){ 450 if(obj->dknown && objects[obj->otyp].oc_name_known){ 451 if(objects[obj->otyp].g_val > 0){ 452 u.uluck += 5; 453 goto valuable; 454 } else { 455 pline("%s is not interested in your junk.", 456 Monnam(mon)); 457 } 458 } else { /* value unknown to @ */ 459 u.uluck++; 460 valuable: 461 if(u.uluck > LUCKMAX) /* dan@ut-ngp */ 462 u.uluck = LUCKMAX; 463 pline("%s graciously accepts your gift.", 464 Monnam(mon)); 465 mpickobj(mon, obj); 466 rloc(mon); 467 return(1); 468 } 469 } 470 } 471 } 472 /* the code following might become part of dropy() */ 473 if(obj->otyp == CRYSKNIFE) 474 obj->otyp = WORM_TOOTH; 475 obj->ox = bhitpos.x; 476 obj->oy = bhitpos.y; 477 obj->nobj = fobj; 478 fobj = obj; 479 /* prevent him from throwing articles to the exit and escaping */ 480 /* subfrombill(obj); */ 481 stackobj(obj); 482 if(Punished && obj == uball && 483 (bhitpos.x != u.ux || bhitpos.y != u.uy)){ 484 freeobj(uchain); 485 unpobj(uchain); 486 if(u.utrap){ 487 if(u.utraptype == TT_PIT) 488 pline("The ball pulls you out of the pit!"); 489 else { 490 long side = 491 rn2(3) ? LEFT_SIDE : RIGHT_SIDE; 492 pline("The ball pulls you out of the bear trap."); 493 pline("Your %s leg is severely damaged.", 494 (side == LEFT_SIDE) ? "left" : "right"); 495 set_wounded_legs(side, 500+rn2(1000)); 496 losehp(2, "thrown ball"); 497 } 498 u.utrap = 0; 499 } 500 unsee(); 501 uchain->nobj = fobj; 502 fobj = uchain; 503 u.ux = uchain->ox = bhitpos.x - u.dx; 504 u.uy = uchain->oy = bhitpos.y - u.dy; 505 setsee(); 506 (void) inshop(); 507 } 508 if(cansee(bhitpos.x, bhitpos.y)) prl(bhitpos.x,bhitpos.y); 509 return(1); 510 } 511 512 /* split obj so that it gets size num */ 513 /* remainder is put in the object structure delivered by this call */ 514 struct obj * 515 splitobj(struct obj *obj, int num) 516 { 517 struct obj *otmp; 518 519 otmp = newobj(0); 520 *otmp = *obj; /* copies whole structure */ 521 otmp->o_id = flags.ident++; 522 otmp->onamelth = 0; 523 obj->quan = num; 524 obj->owt = weight(obj); 525 otmp->quan -= num; 526 otmp->owt = weight(otmp); /* -= obj->owt ? */ 527 obj->nobj = otmp; 528 if(obj->unpaid) splitbill(obj,otmp); 529 return(otmp); 530 } 531 532 void 533 more_experienced(int exp, int rexp) 534 { 535 extern char pl_character[]; 536 537 u.uexp += exp; 538 u.urexp += 4*exp + rexp; 539 if(exp) flags.botl = 1; 540 if(u.urexp >= ((pl_character[0] == 'W') ? 1000 : 2000)) 541 flags.beginner = 0; 542 } 543 544 void 545 set_wounded_legs(long side, int timex) 546 { 547 if(!Wounded_legs || (Wounded_legs & TIMEOUT)) 548 Wounded_legs |= side + timex; 549 else 550 Wounded_legs |= side; 551 } 552 553 void 554 heal_legs() 555 { 556 if(Wounded_legs) { 557 if((Wounded_legs & BOTH_SIDES) == BOTH_SIDES) 558 pline("Your legs feel somewhat better."); 559 else 560 pline("Your leg feels somewhat better."); 561 Wounded_legs = 0; 562 } 563 } 564