1 /* $NetBSD: pack.c,v 1.10 2008/01/14 03:50:02 dholland 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.10 2008/01/14 03:50:02 dholland 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(object *obj, object *pack, int condense) 62 { 63 object *op; 64 65 if (condense) { 66 if ((op = check_duplicate(obj, pack)) != NULL) { 67 free_object(obj); 68 return(op); 69 } else { 70 obj->ichar = next_avail_ichar(); 71 } 72 } 73 if (pack->next_object == 0) { 74 pack->next_object = obj; 75 } else { 76 op = pack->next_object; 77 78 while (op->next_object) { 79 op = op->next_object; 80 } 81 op->next_object = obj; 82 } 83 obj->next_object = 0; 84 return(obj); 85 } 86 87 void 88 take_from_pack(object *obj, object *pack) 89 { 90 while (pack->next_object != obj) { 91 pack = pack->next_object; 92 } 93 pack->next_object = pack->next_object->next_object; 94 } 95 96 /* Note: *status is set to 0 if the rogue attempts to pick up a scroll 97 * of scare-monster and it turns to dust. *status is otherwise set to 1. 98 */ 99 100 object * 101 pick_up(int row, int col, short *status) 102 { 103 object *obj; 104 105 *status = 1; 106 107 if (levitate) { 108 messagef(0, "you're floating in the air!"); 109 return NULL; 110 } 111 obj = object_at(&level_objects, row, col); 112 if (!obj) { 113 messagef(1, "pick_up(): inconsistent"); 114 return(obj); 115 } 116 if ( (obj->what_is == SCROL) && 117 (obj->which_kind == SCARE_MONSTER) && 118 obj->picked_up) { 119 messagef(0, "the scroll turns to dust as you pick it up"); 120 dungeon[row][col] &= (~OBJECT); 121 vanish(obj, 0, &level_objects); 122 *status = 0; 123 if (id_scrolls[SCARE_MONSTER].id_status == UNIDENTIFIED) { 124 id_scrolls[SCARE_MONSTER].id_status = IDENTIFIED; 125 } 126 return NULL; 127 } 128 if (obj->what_is == GOLD) { 129 rogue.gold += obj->quantity; 130 dungeon[row][col] &= ~(OBJECT); 131 take_from_pack(obj, &level_objects); 132 print_stats(STAT_GOLD); 133 return(obj); /* obj will be free_object()ed in caller */ 134 } 135 if (pack_count(obj) >= MAX_PACK_COUNT) { 136 messagef(1, "pack too full"); 137 return NULL; 138 } 139 dungeon[row][col] &= ~(OBJECT); 140 take_from_pack(obj, &level_objects); 141 obj = add_to_pack(obj, &rogue.pack, 1); 142 obj->picked_up = 1; 143 return(obj); 144 } 145 146 void 147 drop(void) 148 { 149 object *obj, *new; 150 short ch; 151 char desc[DCOLS]; 152 153 if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) { 154 messagef(0, "there's already something there"); 155 return; 156 } 157 if (!rogue.pack.next_object) { 158 messagef(0, "you have nothing to drop"); 159 return; 160 } 161 if ((ch = pack_letter("drop what?", ALL_OBJECTS)) == CANCEL) { 162 return; 163 } 164 if (!(obj = get_letter_object(ch))) { 165 messagef(0, "no such item."); 166 return; 167 } 168 if (obj->in_use_flags & BEING_WIELDED) { 169 if (obj->is_cursed) { 170 messagef(0, "%s", curse_message); 171 return; 172 } 173 unwield(rogue.weapon); 174 } else if (obj->in_use_flags & BEING_WORN) { 175 if (obj->is_cursed) { 176 messagef(0, "%s", curse_message); 177 return; 178 } 179 mv_aquatars(); 180 unwear(rogue.armor); 181 print_stats(STAT_ARMOR); 182 } else if (obj->in_use_flags & ON_EITHER_HAND) { 183 if (obj->is_cursed) { 184 messagef(0, "%s", curse_message); 185 return; 186 } 187 un_put_on(obj); 188 } 189 obj->row = rogue.row; 190 obj->col = rogue.col; 191 192 if ((obj->quantity > 1) && (obj->what_is != WEAPON)) { 193 obj->quantity--; 194 new = alloc_object(); 195 *new = *obj; 196 new->quantity = 1; 197 obj = new; 198 } else { 199 obj->ichar = 'L'; 200 take_from_pack(obj, &rogue.pack); 201 } 202 place_at(obj, rogue.row, rogue.col); 203 get_desc(obj, desc, sizeof(desc)); 204 messagef(0, "dropped %s", desc); 205 (void)reg_move(); 206 } 207 208 object * 209 check_duplicate(object *obj, object *pack) 210 { 211 object *op; 212 213 if (!(obj->what_is & (WEAPON | FOOD | SCROL | POTION))) { 214 return(0); 215 } 216 if ((obj->what_is == FOOD) && (obj->which_kind == FRUIT)) { 217 return(0); 218 } 219 op = pack->next_object; 220 221 while (op) { 222 if ((op->what_is == obj->what_is) && 223 (op->which_kind == obj->which_kind)) { 224 225 if ((obj->what_is != WEAPON) || 226 ((obj->what_is == WEAPON) && 227 ((obj->which_kind == ARROW) || 228 (obj->which_kind == DAGGER) || 229 (obj->which_kind == DART) || 230 (obj->which_kind == SHURIKEN)) && 231 (obj->quiver == op->quiver))) { 232 op->quantity += obj->quantity; 233 return(op); 234 } 235 } 236 op = op->next_object; 237 } 238 return(0); 239 } 240 241 short 242 next_avail_ichar(void) 243 { 244 object *obj; 245 int i; 246 boolean ichars[26]; 247 248 for (i = 0; i < 26; i++) { 249 ichars[i] = 0; 250 } 251 obj = rogue.pack.next_object; 252 while (obj) { 253 if (obj->ichar >= 'a' && obj->ichar <= 'z') { 254 ichars[(obj->ichar - 'a')] = 1; 255 } 256 obj = obj->next_object; 257 } 258 for (i = 0; i < 26; i++) { 259 if (!ichars[i]) { 260 return(i + 'a'); 261 } 262 } 263 return('?'); 264 } 265 266 void 267 wait_for_ack(void) 268 { 269 while (rgetchar() != ' ') 270 ; 271 } 272 273 short 274 pack_letter(const char *prompt, unsigned short mask) 275 { 276 short ch; 277 unsigned short tmask = mask; 278 279 if (!mask_pack(&rogue.pack, mask)) { 280 messagef(0, "nothing appropriate"); 281 return(CANCEL); 282 } 283 for (;;) { 284 285 messagef(0, "%s", prompt); 286 287 for (;;) { 288 ch = rgetchar(); 289 if (!is_pack_letter(&ch, &mask)) { 290 sound_bell(); 291 } else { 292 break; 293 } 294 } 295 296 if (ch == LIST) { 297 check_message(); 298 mask = tmask; 299 inventory(&rogue.pack, mask); 300 } else { 301 break; 302 } 303 mask = tmask; 304 } 305 check_message(); 306 return(ch); 307 } 308 309 void 310 take_off(void) 311 { 312 char desc[DCOLS]; 313 object *obj; 314 315 if (rogue.armor) { 316 if (rogue.armor->is_cursed) { 317 messagef(0, "%s", curse_message); 318 } else { 319 mv_aquatars(); 320 obj = rogue.armor; 321 unwear(rogue.armor); 322 get_desc(obj, desc, sizeof(desc)); 323 messagef(0, "was wearing %s", desc); 324 print_stats(STAT_ARMOR); 325 (void)reg_move(); 326 } 327 } else { 328 messagef(0, "not wearing any"); 329 } 330 } 331 332 void 333 wear(void) 334 { 335 short ch; 336 object *obj; 337 char desc[DCOLS]; 338 339 if (rogue.armor) { 340 messagef(0, "you're already wearing some"); 341 return; 342 } 343 ch = pack_letter("wear what?", ARMOR); 344 345 if (ch == CANCEL) { 346 return; 347 } 348 if (!(obj = get_letter_object(ch))) { 349 messagef(0, "no such item."); 350 return; 351 } 352 if (obj->what_is != ARMOR) { 353 messagef(0, "you can't wear that"); 354 return; 355 } 356 obj->identified = 1; 357 get_desc(obj, desc, sizeof(desc)); 358 messagef(0, "wearing %s", desc); 359 do_wear(obj); 360 print_stats(STAT_ARMOR); 361 (void)reg_move(); 362 } 363 364 void 365 unwear(object *obj) 366 { 367 if (obj) { 368 obj->in_use_flags &= (~BEING_WORN); 369 } 370 rogue.armor = NULL; 371 } 372 373 void 374 do_wear(object *obj) 375 { 376 rogue.armor = obj; 377 obj->in_use_flags |= BEING_WORN; 378 obj->identified = 1; 379 } 380 381 void 382 wield(void) 383 { 384 short ch; 385 object *obj; 386 char desc[DCOLS]; 387 388 if (rogue.weapon && rogue.weapon->is_cursed) { 389 messagef(0, "%s", curse_message); 390 return; 391 } 392 ch = pack_letter("wield what?", WEAPON); 393 394 if (ch == CANCEL) { 395 return; 396 } 397 if (!(obj = get_letter_object(ch))) { 398 messagef(0, "No such item."); 399 return; 400 } 401 if (obj->what_is & (ARMOR | RING)) { 402 messagef(0, "you can't wield %s", 403 ((obj->what_is == ARMOR) ? "armor" : "rings")); 404 return; 405 } 406 if (obj->in_use_flags & BEING_WIELDED) { 407 messagef(0, "in use"); 408 } else { 409 unwield(rogue.weapon); 410 get_desc(obj, desc, sizeof(desc)); 411 messagef(0, "wielding %s", desc); 412 do_wield(obj); 413 (void)reg_move(); 414 } 415 } 416 417 void 418 do_wield(object *obj) 419 { 420 rogue.weapon = obj; 421 obj->in_use_flags |= BEING_WIELDED; 422 } 423 424 void 425 unwield(object *obj) 426 { 427 if (obj) { 428 obj->in_use_flags &= (~BEING_WIELDED); 429 } 430 rogue.weapon = NULL; 431 } 432 433 void 434 call_it(void) 435 { 436 short ch; 437 object *obj; 438 struct id *id_table; 439 char buf[MAX_TITLE_LENGTH+2]; 440 441 ch = pack_letter("call what?", (SCROL | POTION | WAND | RING)); 442 443 if (ch == CANCEL) { 444 return; 445 } 446 if (!(obj = get_letter_object(ch))) { 447 messagef(0, "no such item."); 448 return; 449 } 450 if (!(obj->what_is & (SCROL | POTION | WAND | RING))) { 451 messagef(0, "surely you already know what that's called"); 452 return; 453 } 454 id_table = get_id_table(obj); 455 456 if (get_input_line("call it:", "", buf, sizeof(buf), 457 id_table[obj->which_kind].title, 1, 1)) { 458 id_table[obj->which_kind].id_status = CALLED; 459 (void)strlcpy(id_table[obj->which_kind].title, buf, 460 sizeof(id_table[obj->which_kind].title)); 461 } 462 } 463 464 short 465 pack_count(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(const object *pack, unsigned short mask) 493 { 494 while (pack->next_object) { 495 pack = pack->next_object; 496 if (pack->what_is & mask) { 497 return(1); 498 } 499 } 500 return(0); 501 } 502 503 boolean 504 is_pack_letter(short *c, unsigned short *mask) 505 { 506 if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') || 507 (*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) { 508 switch(*c) { 509 case '?': 510 *mask = SCROL; 511 break; 512 case '!': 513 *mask = POTION; 514 break; 515 case ':': 516 *mask = FOOD; 517 break; 518 case ')': 519 *mask = WEAPON; 520 break; 521 case ']': 522 *mask = ARMOR; 523 break; 524 case '/': 525 *mask = WAND; 526 break; 527 case '=': 528 *mask = RING; 529 break; 530 case ',': 531 *mask = AMULET; 532 break; 533 } 534 *c = LIST; 535 return(1); 536 } 537 return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST)); 538 } 539 540 boolean 541 has_amulet(void) 542 { 543 return(mask_pack(&rogue.pack, AMULET)); 544 } 545 546 void 547 kick_into_pack(void) 548 { 549 object *obj; 550 char desc[DCOLS]; 551 short stat; 552 553 if (!(dungeon[rogue.row][rogue.col] & OBJECT)) { 554 messagef(0, "nothing here"); 555 } else { 556 if ((obj = pick_up(rogue.row, rogue.col, &stat)) != NULL) { 557 get_desc(obj, desc, sizeof(desc)); 558 if (obj->what_is == GOLD) { 559 messagef(0, "%s", desc); 560 free_object(obj); 561 } else { 562 messagef(0, "%s(%c)", desc, obj->ichar); 563 } 564 } 565 if (obj || (!stat)) { 566 (void)reg_move(); 567 } 568 } 569 } 570