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