1 /* $NetBSD: pack.c,v 1.7 2003/08/07 09:37:39 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Timothy C. Stoehr. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. 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 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)pack.c 8.1 (Berkeley) 5/31/93"; 39 #else 40 __RCSID("$NetBSD: pack.c,v 1.7 2003/08/07 09:37:39 agc Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 /* 45 * pack.c 46 * 47 * This source herein may be modified and/or distributed by anybody who 48 * so desires, with the following restrictions: 49 * 1.) No portion of this notice shall be removed. 50 * 2.) Credit shall not be taken for the creation of this source. 51 * 3.) This code is not to be traded, sold, or used for personal 52 * gain or profit. 53 * 54 */ 55 56 #include "rogue.h" 57 58 const char *curse_message = "you can't, it appears to be cursed"; 59 60 object * 61 add_to_pack(obj, pack, condense) 62 object *obj, *pack; 63 int condense; 64 { 65 object *op; 66 67 if (condense) { 68 if ((op = check_duplicate(obj, pack)) != NULL) { 69 free_object(obj); 70 return(op); 71 } else { 72 obj->ichar = next_avail_ichar(); 73 } 74 } 75 if (pack->next_object == 0) { 76 pack->next_object = obj; 77 } else { 78 op = pack->next_object; 79 80 while (op->next_object) { 81 op = op->next_object; 82 } 83 op->next_object = obj; 84 } 85 obj->next_object = 0; 86 return(obj); 87 } 88 89 void 90 take_from_pack(obj, pack) 91 object *obj, *pack; 92 { 93 while (pack->next_object != obj) { 94 pack = pack->next_object; 95 } 96 pack->next_object = pack->next_object->next_object; 97 } 98 99 /* Note: *status is set to 0 if the rogue attempts to pick up a scroll 100 * of scare-monster and it turns to dust. *status is otherwise set to 1. 101 */ 102 103 object * 104 pick_up(row, col, status) 105 short *status; 106 int row, col; 107 { 108 object *obj; 109 110 *status = 1; 111 112 if (levitate) { 113 message("you're floating in the air!", 0); 114 return((object *) 0); 115 } 116 obj = object_at(&level_objects, row, col); 117 if (!obj) { 118 message("pick_up(): inconsistent", 1); 119 return(obj); 120 } 121 if ( (obj->what_is == SCROL) && 122 (obj->which_kind == SCARE_MONSTER) && 123 obj->picked_up) { 124 message("the scroll turns to dust as you pick it up", 0); 125 dungeon[row][col] &= (~OBJECT); 126 vanish(obj, 0, &level_objects); 127 *status = 0; 128 if (id_scrolls[SCARE_MONSTER].id_status == UNIDENTIFIED) { 129 id_scrolls[SCARE_MONSTER].id_status = IDENTIFIED; 130 } 131 return((object *) 0); 132 } 133 if (obj->what_is == GOLD) { 134 rogue.gold += obj->quantity; 135 dungeon[row][col] &= ~(OBJECT); 136 take_from_pack(obj, &level_objects); 137 print_stats(STAT_GOLD); 138 return(obj); /* obj will be free_object()ed in caller */ 139 } 140 if (pack_count(obj) >= MAX_PACK_COUNT) { 141 message("pack too full", 1); 142 return((object *) 0); 143 } 144 dungeon[row][col] &= ~(OBJECT); 145 take_from_pack(obj, &level_objects); 146 obj = add_to_pack(obj, &rogue.pack, 1); 147 obj->picked_up = 1; 148 return(obj); 149 } 150 151 void 152 drop() 153 { 154 object *obj, *new; 155 short ch; 156 char desc[DCOLS]; 157 158 if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) { 159 message("there's already something there", 0); 160 return; 161 } 162 if (!rogue.pack.next_object) { 163 message("you have nothing to drop", 0); 164 return; 165 } 166 if ((ch = pack_letter("drop what?", ALL_OBJECTS)) == CANCEL) { 167 return; 168 } 169 if (!(obj = get_letter_object(ch))) { 170 message("no such item.", 0); 171 return; 172 } 173 if (obj->in_use_flags & BEING_WIELDED) { 174 if (obj->is_cursed) { 175 message(curse_message, 0); 176 return; 177 } 178 unwield(rogue.weapon); 179 } else if (obj->in_use_flags & BEING_WORN) { 180 if (obj->is_cursed) { 181 message(curse_message, 0); 182 return; 183 } 184 mv_aquatars(); 185 unwear(rogue.armor); 186 print_stats(STAT_ARMOR); 187 } else if (obj->in_use_flags & ON_EITHER_HAND) { 188 if (obj->is_cursed) { 189 message(curse_message, 0); 190 return; 191 } 192 un_put_on(obj); 193 } 194 obj->row = rogue.row; 195 obj->col = rogue.col; 196 197 if ((obj->quantity > 1) && (obj->what_is != WEAPON)) { 198 obj->quantity--; 199 new = alloc_object(); 200 *new = *obj; 201 new->quantity = 1; 202 obj = new; 203 } else { 204 obj->ichar = 'L'; 205 take_from_pack(obj, &rogue.pack); 206 } 207 place_at(obj, rogue.row, rogue.col); 208 (void) strcpy(desc, "dropped "); 209 get_desc(obj, desc+8); 210 message(desc, 0); 211 (void) reg_move(); 212 } 213 214 object * 215 check_duplicate(obj, pack) 216 object *obj, *pack; 217 { 218 object *op; 219 220 if (!(obj->what_is & (WEAPON | FOOD | SCROL | POTION))) { 221 return(0); 222 } 223 if ((obj->what_is == FOOD) && (obj->which_kind == FRUIT)) { 224 return(0); 225 } 226 op = pack->next_object; 227 228 while (op) { 229 if ((op->what_is == obj->what_is) && 230 (op->which_kind == obj->which_kind)) { 231 232 if ((obj->what_is != WEAPON) || 233 ((obj->what_is == WEAPON) && 234 ((obj->which_kind == ARROW) || 235 (obj->which_kind == DAGGER) || 236 (obj->which_kind == DART) || 237 (obj->which_kind == SHURIKEN)) && 238 (obj->quiver == op->quiver))) { 239 op->quantity += obj->quantity; 240 return(op); 241 } 242 } 243 op = op->next_object; 244 } 245 return(0); 246 } 247 248 short 249 next_avail_ichar() 250 { 251 object *obj; 252 int i; 253 boolean ichars[26]; 254 255 for (i = 0; i < 26; i++) { 256 ichars[i] = 0; 257 } 258 obj = rogue.pack.next_object; 259 while (obj) { 260 ichars[(obj->ichar - 'a')] = 1; 261 obj = obj->next_object; 262 } 263 for (i = 0; i < 26; i++) { 264 if (!ichars[i]) { 265 return(i + 'a'); 266 } 267 } 268 return('?'); 269 } 270 271 void 272 wait_for_ack() 273 { 274 while (rgetchar() != ' ') ; 275 } 276 277 short 278 pack_letter(prompt, mask) 279 const char *prompt; 280 unsigned short mask; 281 { 282 short ch; 283 unsigned short tmask = mask; 284 285 if (!mask_pack(&rogue.pack, mask)) { 286 message("nothing appropriate", 0); 287 return(CANCEL); 288 } 289 for (;;) { 290 291 message(prompt, 0); 292 293 for (;;) { 294 ch = rgetchar(); 295 if (!is_pack_letter(&ch, &mask)) { 296 sound_bell(); 297 } else { 298 break; 299 } 300 } 301 302 if (ch == LIST) { 303 check_message(); 304 mask = tmask; 305 inventory(&rogue.pack, mask); 306 } else { 307 break; 308 } 309 mask = tmask; 310 } 311 check_message(); 312 return(ch); 313 } 314 315 void 316 take_off() 317 { 318 char desc[DCOLS]; 319 object *obj; 320 321 if (rogue.armor) { 322 if (rogue.armor->is_cursed) { 323 message(curse_message, 0); 324 } else { 325 mv_aquatars(); 326 obj = rogue.armor; 327 unwear(rogue.armor); 328 (void) strcpy(desc, "was wearing "); 329 get_desc(obj, desc+12); 330 message(desc, 0); 331 print_stats(STAT_ARMOR); 332 (void) reg_move(); 333 } 334 } else { 335 message("not wearing any", 0); 336 } 337 } 338 339 void 340 wear() 341 { 342 short ch; 343 object *obj; 344 char desc[DCOLS]; 345 346 if (rogue.armor) { 347 message("your already wearing some", 0); 348 return; 349 } 350 ch = pack_letter("wear what?", ARMOR); 351 352 if (ch == CANCEL) { 353 return; 354 } 355 if (!(obj = get_letter_object(ch))) { 356 message("no such item.", 0); 357 return; 358 } 359 if (obj->what_is != ARMOR) { 360 message("you can't wear that", 0); 361 return; 362 } 363 obj->identified = 1; 364 (void) strcpy(desc, "wearing "); 365 get_desc(obj, desc + 8); 366 message(desc, 0); 367 do_wear(obj); 368 print_stats(STAT_ARMOR); 369 (void) reg_move(); 370 } 371 372 void 373 unwear(obj) 374 object *obj; 375 { 376 if (obj) { 377 obj->in_use_flags &= (~BEING_WORN); 378 } 379 rogue.armor = (object *) 0; 380 } 381 382 void 383 do_wear(obj) 384 object *obj; 385 { 386 rogue.armor = obj; 387 obj->in_use_flags |= BEING_WORN; 388 obj->identified = 1; 389 } 390 391 void 392 wield() 393 { 394 short ch; 395 object *obj; 396 char desc[DCOLS]; 397 398 if (rogue.weapon && rogue.weapon->is_cursed) { 399 message(curse_message, 0); 400 return; 401 } 402 ch = pack_letter("wield what?", WEAPON); 403 404 if (ch == CANCEL) { 405 return; 406 } 407 if (!(obj = get_letter_object(ch))) { 408 message("No such item.", 0); 409 return; 410 } 411 if (obj->what_is & (ARMOR | RING)) { 412 sprintf(desc, "you can't wield %s", 413 ((obj->what_is == ARMOR) ? "armor" : "rings")); 414 message(desc, 0); 415 return; 416 } 417 if (obj->in_use_flags & BEING_WIELDED) { 418 message("in use", 0); 419 } else { 420 unwield(rogue.weapon); 421 (void) strcpy(desc, "wielding "); 422 get_desc(obj, desc + 9); 423 message(desc, 0); 424 do_wield(obj); 425 (void) reg_move(); 426 } 427 } 428 429 void 430 do_wield(obj) 431 object *obj; 432 { 433 rogue.weapon = obj; 434 obj->in_use_flags |= BEING_WIELDED; 435 } 436 437 void 438 unwield(obj) 439 object *obj; 440 { 441 if (obj) { 442 obj->in_use_flags &= (~BEING_WIELDED); 443 } 444 rogue.weapon = (object *) 0; 445 } 446 447 void 448 call_it() 449 { 450 short ch; 451 object *obj; 452 struct id *id_table; 453 char buf[MAX_TITLE_LENGTH+2]; 454 455 ch = pack_letter("call what?", (SCROL | POTION | WAND | RING)); 456 457 if (ch == CANCEL) { 458 return; 459 } 460 if (!(obj = get_letter_object(ch))) { 461 message("no such item.", 0); 462 return; 463 } 464 if (!(obj->what_is & (SCROL | POTION | WAND | RING))) { 465 message("surely you already know what that's called", 0); 466 return; 467 } 468 id_table = get_id_table(obj); 469 470 if (get_input_line("call it:","",buf,id_table[obj->which_kind].title,1,1)) { 471 id_table[obj->which_kind].id_status = CALLED; 472 (void) strcpy(id_table[obj->which_kind].title, buf); 473 } 474 } 475 476 short 477 pack_count(new_obj) 478 const object *new_obj; 479 { 480 object *obj; 481 short count = 0; 482 483 obj = rogue.pack.next_object; 484 485 while (obj) { 486 if (obj->what_is != WEAPON) { 487 count += obj->quantity; 488 } else if (!new_obj) { 489 count++; 490 } else if ((new_obj->what_is != WEAPON) || 491 ((obj->which_kind != ARROW) && 492 (obj->which_kind != DAGGER) && 493 (obj->which_kind != DART) && 494 (obj->which_kind != SHURIKEN)) || 495 (new_obj->which_kind != obj->which_kind) || 496 (obj->quiver != new_obj->quiver)) { 497 count++; 498 } 499 obj = obj->next_object; 500 } 501 return(count); 502 } 503 504 boolean 505 mask_pack(pack, mask) 506 const object *pack; 507 unsigned short mask; 508 { 509 while (pack->next_object) { 510 pack = pack->next_object; 511 if (pack->what_is & mask) { 512 return(1); 513 } 514 } 515 return(0); 516 } 517 518 boolean 519 is_pack_letter(c, mask) 520 short *c; 521 unsigned short *mask; 522 { 523 if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') || 524 (*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) { 525 switch(*c) { 526 case '?': 527 *mask = SCROL; 528 break; 529 case '!': 530 *mask = POTION; 531 break; 532 case ':': 533 *mask = FOOD; 534 break; 535 case ')': 536 *mask = WEAPON; 537 break; 538 case ']': 539 *mask = ARMOR; 540 break; 541 case '/': 542 *mask = WAND; 543 break; 544 case '=': 545 *mask = RING; 546 break; 547 case ',': 548 *mask = AMULET; 549 break; 550 } 551 *c = LIST; 552 return(1); 553 } 554 return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST)); 555 } 556 557 boolean 558 has_amulet() 559 { 560 return(mask_pack(&rogue.pack, AMULET)); 561 } 562 563 void 564 kick_into_pack() 565 { 566 object *obj; 567 char desc[DCOLS]; 568 short n, stat; 569 570 if (!(dungeon[rogue.row][rogue.col] & OBJECT)) { 571 message("nothing here", 0); 572 } else { 573 if ((obj = pick_up(rogue.row, rogue.col, &stat)) != NULL) { 574 get_desc(obj, desc); 575 if (obj->what_is == GOLD) { 576 message(desc, 0); 577 free_object(obj); 578 } else { 579 n = strlen(desc); 580 desc[n] = '('; 581 desc[n+1] = obj->ichar; 582 desc[n+2] = ')'; 583 desc[n+3] = 0; 584 message(desc, 0); 585 } 586 } 587 if (obj || (!stat)) { 588 (void) reg_move(); 589 } 590 } 591 } 592