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