1/* SCCS Id: @(#)pickup.c 3.4 2003/07/27 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5/* 6 * Contains code for picking objects up, and container use. 7 */ 8 9#include "hack.h" 10 11STATIC_DCL void FDECL(simple_look, (struct obj *,BOOLEAN_P)); 12#ifndef GOLDOBJ 13STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *, 14 const char *,struct obj *,BOOLEAN_P,BOOLEAN_P,int *)); 15#else 16STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *, 17 const char *,struct obj *,BOOLEAN_P,int *)); 18#endif 19STATIC_DCL void FDECL(check_here, (BOOLEAN_P)); 20STATIC_DCL boolean FDECL(n_or_more, (struct obj *)); 21STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *)); 22#if 0 /* not used */ 23STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *)); 24#endif 25STATIC_DCL int FDECL(autopick, (struct obj*, int, menu_item **)); 26STATIC_DCL int FDECL(count_categories, (struct obj *,int)); 27STATIC_DCL long FDECL(carry_count, 28 (struct obj *,struct obj *,long,BOOLEAN_P,int *,int *)); 29STATIC_DCL int FDECL(lift_object, (struct obj *,struct obj *,long *,BOOLEAN_P)); 30STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *,int)); 31STATIC_PTR int FDECL(in_container,(struct obj *)); 32STATIC_PTR int FDECL(ck_bag,(struct obj *)); 33STATIC_PTR int FDECL(out_container,(struct obj *)); 34STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *)); 35STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *)); 36STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P)); 37STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P)); 38STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P)); 39STATIC_DCL boolean FDECL(able_to_loot, (int, int)); 40STATIC_DCL boolean FDECL(mon_beside, (int, int)); 41 42/* define for query_objlist() and autopickup() */ 43#define FOLLOW(curr, flags) \ 44 (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj) 45 46/* 47 * How much the weight of the given container will change when the given 48 * object is removed from it. This calculation must match the one used 49 * by weight() in mkobj.c. 50 */ 51#define DELTA_CWT(cont,obj) \ 52 ((cont)->cursed ? (obj)->owt * 2 : \ 53 1 + ((obj)->owt / ((cont)->blessed ? 4 : 2))) 54#define GOLD_WT(n) (((n) + 50L) / 100L) 55/* if you can figure this out, give yourself a hearty pat on the back... */ 56#define GOLD_CAPACITY(w,n) (((w) * -100L) - ((n) + 50L) - 1L) 57 58static const char moderateloadmsg[] = "You have a little trouble lifting"; 59static const char nearloadmsg[] = "You have much trouble lifting"; 60static const char overloadmsg[] = "You have extreme difficulty lifting"; 61 62/* BUG: this lets you look at cockatrice corpses while blind without 63 touching them */ 64/* much simpler version of the look-here code; used by query_classes() */ 65STATIC_OVL void 66simple_look(otmp, here) 67struct obj *otmp; /* list of objects */ 68boolean here; /* flag for type of obj list linkage */ 69{ 70 /* Neither of the first two cases is expected to happen, since 71 * we're only called after multiple classes of objects have been 72 * detected, hence multiple objects must be present. 73 */ 74 if (!otmp) { 75 impossible("simple_look(null)"); 76 } else if (!(here ? otmp->nexthere : otmp->nobj)) { 77 pline("%s", doname(otmp)); 78 } else { 79 winid tmpwin = create_nhwindow(NHW_MENU); 80 putstr(tmpwin, 0, ""); 81 do { 82 putstr(tmpwin, 0, doname(otmp)); 83 otmp = here ? otmp->nexthere : otmp->nobj; 84 } while (otmp); 85 display_nhwindow(tmpwin, TRUE); 86 destroy_nhwindow(tmpwin); 87 } 88} 89 90#ifndef GOLDOBJ 91int 92collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount) 93char ilets[]; 94register struct obj *otmp; 95boolean here, incl_gold; 96boolean FDECL((*filter),(OBJ_P)); 97int *itemcount; 98#else 99int 100collect_obj_classes(ilets, otmp, here, filter, itemcount) 101char ilets[]; 102register struct obj *otmp; 103boolean here; 104boolean FDECL((*filter),(OBJ_P)); 105int *itemcount; 106#endif 107{ 108 register int iletct = 0; 109 register char c; 110 111 *itemcount = 0; 112#ifndef GOLDOBJ 113 if (incl_gold) 114 ilets[iletct++] = def_oc_syms[COIN_CLASS]; 115#endif 116 ilets[iletct] = '\0'; /* terminate ilets so that index() will work */ 117 while (otmp) { 118 c = def_oc_syms[(int)otmp->oclass]; 119 if (!index(ilets, c) && (!filter || (*filter)(otmp))) 120 ilets[iletct++] = c, ilets[iletct] = '\0'; 121 *itemcount += 1; 122 otmp = here ? otmp->nexthere : otmp->nobj; 123 } 124 125 return iletct; 126} 127 128/* 129 * Suppose some '?' and '!' objects are present, but '/' objects aren't: 130 * "a" picks all items without further prompting; 131 * "A" steps through all items, asking one by one; 132 * "?" steps through '?' items, asking, and ignores '!' ones; 133 * "/" becomes 'A', since no '/' present; 134 * "?a" or "a?" picks all '?' without further prompting; 135 * "/a" or "a/" becomes 'A' since there aren't any '/' 136 * (bug fix: 3.1.0 thru 3.1.3 treated it as "a"); 137 * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/' 138 * (ie, treated as if it had just been "?a"). 139 */ 140#ifndef GOLDOBJ 141STATIC_OVL boolean 142query_classes(oclasses, one_at_a_time, everything, action, objs, 143 here, incl_gold, menu_on_demand) 144char oclasses[]; 145boolean *one_at_a_time, *everything; 146const char *action; 147struct obj *objs; 148boolean here, incl_gold; 149int *menu_on_demand; 150#else 151STATIC_OVL boolean 152query_classes(oclasses, one_at_a_time, everything, action, objs, 153 here, menu_on_demand) 154char oclasses[]; 155boolean *one_at_a_time, *everything; 156const char *action; 157struct obj *objs; 158boolean here; 159int *menu_on_demand; 160#endif 161{ 162 char ilets[20], inbuf[BUFSZ]; 163 int iletct, oclassct; 164 boolean not_everything; 165 char qbuf[QBUFSZ]; 166 boolean m_seen; 167 int itemcount; 168 169 oclasses[oclassct = 0] = '\0'; 170 *one_at_a_time = *everything = m_seen = FALSE; 171 iletct = collect_obj_classes(ilets, objs, here, 172#ifndef GOLDOBJ 173 incl_gold, 174#endif 175 (boolean FDECL((*),(OBJ_P))) 0, &itemcount); 176 if (iletct == 0) { 177 return FALSE; 178 } else if (iletct == 1) { 179 oclasses[0] = def_char_to_objclass(ilets[0]); 180 oclasses[1] = '\0'; 181 if (itemcount && menu_on_demand) { 182 ilets[iletct++] = 'm'; 183 *menu_on_demand = 0; 184 ilets[iletct] = '\0'; 185 } 186 } else { /* more than one choice available */ 187 const char *where = 0; 188 register char sym, oc_of_sym, *p; 189 /* additional choices */ 190 ilets[iletct++] = ' '; 191 ilets[iletct++] = 'a'; 192 ilets[iletct++] = 'A'; 193 ilets[iletct++] = (objs == invent ? 'i' : ':'); 194 if (menu_on_demand) { 195 ilets[iletct++] = 'm'; 196 *menu_on_demand = 0; 197 } 198 ilets[iletct] = '\0'; 199ask_again: 200 oclasses[oclassct = 0] = '\0'; 201 *one_at_a_time = *everything = FALSE; 202 not_everything = FALSE; 203 Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]", 204 action, ilets); 205 getlin(qbuf,inbuf); 206 if (*inbuf == '\033') return FALSE; 207 208 for (p = inbuf; (sym = *p++); ) { 209 /* new A function (selective all) added by GAN 01/09/87 */ 210 if (sym == ' ') continue; 211 else if (sym == 'A') *one_at_a_time = TRUE; 212 else if (sym == 'a') *everything = TRUE; 213 else if (sym == ':') { 214 simple_look(objs, here); /* dumb if objs==invent */ 215 goto ask_again; 216 } else if (sym == 'i') { 217 (void) display_inventory((char *)0, TRUE); 218 goto ask_again; 219 } else if (sym == 'm') { 220 m_seen = TRUE; 221 } else { 222 oc_of_sym = def_char_to_objclass(sym); 223 if (index(ilets,sym)) { 224 add_valid_menu_class(oc_of_sym); 225 oclasses[oclassct++] = oc_of_sym; 226 oclasses[oclassct] = '\0'; 227 } else { 228 if (!where) 229 where = !strcmp(action,"pick up") ? "here" : 230 !strcmp(action,"take out") ? 231 "inside" : ""; 232 if (*where) 233 There("are no %c's %s.", sym, where); 234 else 235 You("have no %c's.", sym); 236 not_everything = TRUE; 237 } 238 } 239 } 240 if (m_seen && menu_on_demand) { 241 *menu_on_demand = (*everything || !oclassct) ? -2 : -3; 242 return FALSE; 243 } 244 if (!oclassct && (!*everything || not_everything)) { 245 /* didn't pick anything, 246 or tried to pick something that's not present */ 247 *one_at_a_time = TRUE; /* force 'A' */ 248 *everything = FALSE; /* inhibit 'a' */ 249 } 250 } 251 return TRUE; 252} 253 254/* look at the objects at our location, unless there are too many of them */ 255STATIC_OVL void 256check_here(picked_some) 257boolean picked_some; 258{ 259 register struct obj *obj; 260 register int ct = 0; 261 262 /* count the objects here */ 263 for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) { 264 if (obj != uchain) 265 ct++; 266 } 267 268 /* If there are objects here, take a look. */ 269 if (ct) { 270 if (flags.run) nomul(0); 271 flush_screen(1); 272 (void) look_here(ct, picked_some); 273 } else { 274 read_engr_at(u.ux,u.uy); 275 } 276} 277 278/* Value set by query_objlist() for n_or_more(). */ 279static long val_for_n_or_more; 280 281/* query_objlist callback: return TRUE if obj's count is >= reference value */ 282STATIC_OVL boolean 283n_or_more(obj) 284struct obj *obj; 285{ 286 if (obj == uchain) return FALSE; 287 return (obj->quan >= val_for_n_or_more); 288} 289 290/* List of valid menu classes for query_objlist() and allow_category callback */ 291static char valid_menu_classes[MAXOCLASSES + 2]; 292 293void 294add_valid_menu_class(c) 295int c; 296{ 297 static int vmc_count = 0; 298 299 if (c == 0) /* reset */ 300 vmc_count = 0; 301 else 302 valid_menu_classes[vmc_count++] = (char)c; 303 valid_menu_classes[vmc_count] = '\0'; 304} 305 306/* query_objlist callback: return TRUE if not uchain */ 307STATIC_OVL boolean 308all_but_uchain(obj) 309struct obj *obj; 310{ 311 return (obj != uchain); 312} 313 314/* query_objlist callback: return TRUE */ 315/*ARGSUSED*/ 316boolean 317allow_all(obj) 318struct obj *obj; 319{ 320 return TRUE; 321} 322 323boolean 324allow_category(obj) 325struct obj *obj; 326{ 327 if (Role_if(PM_PRIEST)) obj->bknown = TRUE; 328 if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) || 329 (index(valid_menu_classes, obj->oclass) != (char *)0)) 330 return TRUE; 331 else if (((index(valid_menu_classes,'U') != (char *)0) && 332 (obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed))) 333 return TRUE; 334 else if (((index(valid_menu_classes,'B') != (char *)0) && 335 (obj->oclass != COIN_CLASS && obj->bknown && obj->blessed))) 336 return TRUE; 337 else if (((index(valid_menu_classes,'C') != (char *)0) && 338 (obj->oclass != COIN_CLASS && obj->bknown && obj->cursed))) 339 return TRUE; 340 else if (((index(valid_menu_classes,'X') != (char *)0) && 341 (obj->oclass != COIN_CLASS && !obj->bknown))) 342 return TRUE; 343 else 344 return FALSE; 345} 346 347#if 0 /* not used */ 348/* query_objlist callback: return TRUE if valid category (class), no uchain */ 349STATIC_OVL boolean 350allow_cat_no_uchain(obj) 351struct obj *obj; 352{ 353 if ((obj != uchain) && 354 (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) || 355 (index(valid_menu_classes, obj->oclass) != (char *)0))) 356 return TRUE; 357 else 358 return FALSE; 359} 360#endif 361 362/* query_objlist callback: return TRUE if valid class and worn */ 363boolean 364is_worn_by_type(otmp) 365register struct obj *otmp; 366{ 367 return((boolean)(!!(otmp->owornmask & 368 (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER))) 369 && (index(valid_menu_classes, otmp->oclass) != (char *)0)); 370} 371 372/* 373 * Have the hero pick things from the ground 374 * or a monster's inventory if swallowed. 375 * 376 * Arg what: 377 * >0 autopickup 378 * =0 interactive 379 * <0 pickup count of something 380 * 381 * Returns 1 if tried to pick something up, whether 382 * or not it succeeded. 383 */ 384int 385pickup(what) 386int what; /* should be a long */ 387{ 388 int i, n, res, count, n_tried = 0, n_picked = 0; 389 menu_item *pick_list = (menu_item *) 0; 390 boolean autopickup = what > 0; 391 struct obj *objchain; 392 int traverse_how; 393 394 if (what < 0) /* pick N of something */ 395 count = -what; 396 else /* pick anything */ 397 count = 0; 398 399 if (!u.uswallow) { 400 struct trap *ttmp = t_at(u.ux, u.uy); 401 /* no auto-pick if no-pick move, nothing there, or in a pool */ 402 if (autopickup && (flags.nopick || !OBJ_AT(u.ux, u.uy) || 403 (is_pool(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) { 404 read_engr_at(u.ux, u.uy); 405 return (0); 406 } 407 408 /* no pickup if levitating & not on air or water level */ 409 if (!can_reach_floor()) { 410 if ((multi && !flags.run) || (autopickup && !flags.pickup)) 411 read_engr_at(u.ux, u.uy); 412 return (0); 413 } 414 if (ttmp && ttmp->tseen) { 415 /* Allow pickup from holes and trap doors that you escaped 416 * from because that stuff is teetering on the edge just 417 * like you, but not pits, because there is an elevation 418 * discrepancy with stuff in pits. 419 */ 420 if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) && 421 (!u.utrap || (u.utrap && u.utraptype != TT_PIT))) { 422 read_engr_at(u.ux, u.uy); 423 return(0); 424 } 425 } 426 /* multi && !flags.run means they are in the middle of some other 427 * action, or possibly paralyzed, sleeping, etc.... and they just 428 * teleported onto the object. They shouldn't pick it up. 429 */ 430 if ((multi && !flags.run) || (autopickup && !flags.pickup)) { 431 check_here(FALSE); 432 return (0); 433 } 434 if (notake(youmonst.data)) { 435 if (!autopickup) 436 You("are physically incapable of picking anything up."); 437 else 438 check_here(FALSE); 439 return (0); 440 } 441 442 /* if there's anything here, stop running */ 443 if (OBJ_AT(u.ux,u.uy) && flags.run && flags.run != 8 && !flags.nopick) nomul(0); 444 } 445 446 add_valid_menu_class(0); /* reset */ 447 if (!u.uswallow) { 448 objchain = level.objects[u.ux][u.uy]; 449 traverse_how = BY_NEXTHERE; 450 } else { 451 objchain = u.ustuck->minvent; 452 traverse_how = 0; /* nobj */ 453 } 454 /* 455 * Start the actual pickup process. This is split into two main 456 * sections, the newer menu and the older "traditional" methods. 457 * Automatic pickup has been split into its own menu-style routine 458 * to make things less confusing. 459 */ 460 if (autopickup) { 461 n = autopick(objchain, traverse_how, &pick_list); 462 goto menu_pickup; 463 } 464 465 if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) { 466 467 /* use menus exclusively */ 468 if (count) { /* looking for N of something */ 469 char buf[QBUFSZ]; 470 Sprintf(buf, "Pick %d of what?", count); 471 val_for_n_or_more = count; /* set up callback selector */ 472 n = query_objlist(buf, objchain, 473 traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT, 474 &pick_list, PICK_ONE, n_or_more); 475 /* correct counts, if any given */ 476 for (i = 0; i < n; i++) 477 pick_list[i].count = count; 478 } else { 479 n = query_objlist("Pick up what?", objchain, 480 traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT|FEEL_COCKATRICE, 481 &pick_list, PICK_ANY, all_but_uchain); 482 } 483menu_pickup: 484 n_tried = n; 485 for (n_picked = i = 0 ; i < n; i++) { 486 res = pickup_object(pick_list[i].item.a_obj,pick_list[i].count, 487 FALSE); 488 if (res < 0) break; /* can't continue */ 489 n_picked += res; 490 } 491 if (pick_list) free((genericptr_t)pick_list); 492 493 } else { 494 /* old style interface */ 495 int ct = 0; 496 long lcount; 497 boolean all_of_a_type, selective; 498 char oclasses[MAXOCLASSES]; 499 struct obj *obj, *obj2; 500 501 oclasses[0] = '\0'; /* types to consider (empty for all) */ 502 all_of_a_type = TRUE; /* take all of considered types */ 503 selective = FALSE; /* ask for each item */ 504 505 /* check for more than one object */ 506 for (obj = objchain; 507 obj; obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj) 508 ct++; 509 510 if (ct == 1 && count) { 511 /* if only one thing, then pick it */ 512 obj = objchain; 513 lcount = min(obj->quan, (long)count); 514 n_tried++; 515 if (pickup_object(obj, lcount, FALSE) > 0) 516 n_picked++; /* picked something */ 517 goto end_query; 518 519 } else if (ct >= 2) { 520 int via_menu = 0; 521 522 There("are %s objects here.", 523 (ct <= 10) ? "several" : "many"); 524 if (!query_classes(oclasses, &selective, &all_of_a_type, 525 "pick up", objchain, 526 traverse_how == BY_NEXTHERE, 527#ifndef GOLDOBJ 528 FALSE, 529#endif 530 &via_menu)) { 531 if (!via_menu) return (0); 532 n = query_objlist("Pick up what?", 533 objchain, 534 traverse_how|(selective ? 0 : INVORDER_SORT), 535 &pick_list, PICK_ANY, 536 via_menu == -2 ? allow_all : allow_category); 537 goto menu_pickup; 538 } 539 } 540 541 for (obj = objchain; obj; obj = obj2) { 542 if (traverse_how == BY_NEXTHERE) 543 obj2 = obj->nexthere; /* perhaps obj will be picked up */ 544 else 545 obj2 = obj->nobj; 546 lcount = -1L; 547 548 if (!selective && oclasses[0] && !index(oclasses,obj->oclass)) 549 continue; 550 551 if (!all_of_a_type) { 552 char qbuf[BUFSZ]; 553 Sprintf(qbuf, "Pick up %s?", 554 safe_qbuf("", sizeof("Pick up ?"), doname(obj), 555 an(simple_typename(obj->otyp)), "something")); 556 switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) { 557 case 'q': goto end_query; /* out 2 levels */ 558 case 'n': continue; 559 case 'a': 560 all_of_a_type = TRUE; 561 if (selective) { 562 selective = FALSE; 563 oclasses[0] = obj->oclass; 564 oclasses[1] = '\0'; 565 } 566 break; 567 case '#': /* count was entered */ 568 if (!yn_number) continue; /* 0 count => No */ 569 lcount = (long) yn_number; 570 if (lcount > obj->quan) lcount = obj->quan; 571 /* fall thru */ 572 default: /* 'y' */ 573 break; 574 } 575 } 576 if (lcount == -1L) lcount = obj->quan; 577 578 n_tried++; 579 if ((res = pickup_object(obj, lcount, FALSE)) < 0) break; 580 n_picked += res; 581 } 582end_query: 583 ; /* semicolon needed by brain-damaged compilers */ 584 } 585 586 if (!u.uswallow) { 587 if (!OBJ_AT(u.ux,u.uy)) u.uundetected = 0; 588 589 /* position may need updating (invisible hero) */ 590 if (n_picked) newsym(u.ux,u.uy); 591 592 /* see whether there's anything else here, after auto-pickup is done */ 593 if (autopickup) check_here(n_picked > 0); 594 } 595 return (n_tried > 0); 596} 597 598#ifdef AUTOPICKUP_EXCEPTIONS 599boolean 600is_autopickup_exception(obj, grab) 601struct obj *obj; 602boolean grab; /* forced pickup, rather than forced leave behind? */ 603{ 604 /* 605 * Does the text description of this match an exception? 606 */ 607 char *objdesc = makesingular(doname(obj)); 608 struct autopickup_exception *ape = (grab) ? 609 iflags.autopickup_exceptions[AP_GRAB] : 610 iflags.autopickup_exceptions[AP_LEAVE]; 611 while (ape) { 612 if (pmatch(ape->pattern, objdesc)) return TRUE; 613 ape = ape->next; 614 } 615 return FALSE; 616} 617#endif /* AUTOPICKUP_EXCEPTIONS */ 618 619/* 620 * Pick from the given list using flags.pickup_types. Return the number 621 * of items picked (not counts). Create an array that returns pointers 622 * and counts of the items to be picked up. If the number of items 623 * picked is zero, the pickup list is left alone. The caller of this 624 * function must free the pickup list. 625 */ 626STATIC_OVL int 627autopick(olist, follow, pick_list) 628struct obj *olist; /* the object list */ 629int follow; /* how to follow the object list */ 630menu_item **pick_list; /* list of objects and counts to pick up */ 631{ 632 menu_item *pi; /* pick item */ 633 struct obj *curr; 634 int n; 635 const char *otypes = flags.pickup_types; 636 637 /* first count the number of eligible items */ 638 for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) 639 640 641#ifndef AUTOPICKUP_EXCEPTIONS 642 if (!*otypes || index(otypes, curr->oclass)) 643#else 644 if ((!*otypes || index(otypes, curr->oclass) || 645 is_autopickup_exception(curr, TRUE)) && 646 !is_autopickup_exception(curr, FALSE)) 647#endif 648 n++; 649 650 if (n) { 651 *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n); 652 for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) 653#ifndef AUTOPICKUP_EXCEPTIONS 654 if (!*otypes || index(otypes, curr->oclass)) { 655#else 656 if ((!*otypes || index(otypes, curr->oclass) || 657 is_autopickup_exception(curr, TRUE)) && 658 !is_autopickup_exception(curr, FALSE)) { 659#endif 660 pi[n].item.a_obj = curr; 661 pi[n].count = curr->quan; 662 n++; 663 } 664 } 665 return n; 666} 667 668 669/* 670 * Put up a menu using the given object list. Only those objects on the 671 * list that meet the approval of the allow function are displayed. Return 672 * a count of the number of items selected, as well as an allocated array of 673 * menu_items, containing pointers to the objects selected and counts. The 674 * returned counts are guaranteed to be in bounds and non-zero. 675 * 676 * Query flags: 677 * BY_NEXTHERE - Follow object list via nexthere instead of nobj. 678 * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just 679 * use it. 680 * USE_INVLET - Use object's invlet. 681 * INVORDER_SORT - Use hero's pack order. 682 * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow". 683 */ 684int 685query_objlist(qstr, olist, qflags, pick_list, how, allow) 686const char *qstr; /* query string */ 687struct obj *olist; /* the list to pick from */ 688int qflags; /* options to control the query */ 689menu_item **pick_list; /* return list of items picked */ 690int how; /* type of query */ 691boolean FDECL((*allow), (OBJ_P));/* allow function */ 692{ 693 int n; 694 winid win; 695 struct obj *curr, *last; 696 char *pack; 697 anything any; 698 boolean printed_type_name; 699 700 *pick_list = (menu_item *) 0; 701 if (!olist) return 0; 702 703 /* count the number of items allowed */ 704 for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags)) 705 if ((*allow)(curr)) { 706 last = curr; 707 n++; 708 } 709 710 if (n == 0) /* nothing to pick here */ 711 return (qflags & SIGNAL_NOMENU) ? -1 : 0; 712 713 if (n == 1 && (qflags & AUTOSELECT_SINGLE)) { 714 *pick_list = (menu_item *) alloc(sizeof(menu_item)); 715 (*pick_list)->item.a_obj = last; 716 (*pick_list)->count = last->quan; 717 return 1; 718 } 719 720 win = create_nhwindow(NHW_MENU); 721 start_menu(win); 722 any.a_obj = (struct obj *) 0; 723 724 /* 725 * Run through the list and add the objects to the menu. If 726 * INVORDER_SORT is set, we'll run through the list once for 727 * each type so we can group them. The allow function will only 728 * be called once per object in the list. 729 */ 730 pack = flags.inv_order; 731 do { 732 printed_type_name = FALSE; 733 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { 734 if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE && 735 will_feel_cockatrice(curr, FALSE)) { 736 destroy_nhwindow(win); /* stop the menu and revert */ 737 (void) look_here(0, FALSE); 738 return 0; 739 } 740 if ((!(qflags & INVORDER_SORT) || curr->oclass == *pack) 741 && (*allow)(curr)) { 742 743 /* if sorting, print type name (once only) */ 744 if (qflags & INVORDER_SORT && !printed_type_name) { 745 any.a_obj = (struct obj *) 0; 746 add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, 747 let_to_name(*pack, FALSE), MENU_UNSELECTED); 748 printed_type_name = TRUE; 749 } 750 751 any.a_obj = curr; 752 add_menu(win, obj_to_glyph(curr), &any, 753 qflags & USE_INVLET ? curr->invlet : 0, 754 def_oc_syms[(int)objects[curr->otyp].oc_class], 755 ATR_NONE, doname(curr), MENU_UNSELECTED); 756 } 757 } 758 pack++; 759 } while (qflags & INVORDER_SORT && *pack); 760 761 end_menu(win, qstr); 762 n = select_menu(win, how, pick_list); 763 destroy_nhwindow(win); 764 765 if (n > 0) { 766 menu_item *mi; 767 int i; 768 769 /* fix up counts: -1 means no count used => pick all */ 770 for (i = 0, mi = *pick_list; i < n; i++, mi++) 771 if (mi->count == -1L || mi->count > mi->item.a_obj->quan) 772 mi->count = mi->item.a_obj->quan; 773 } else if (n < 0) { 774 n = 0; /* caller's don't expect -1 */ 775 } 776 return n; 777} 778 779/* 780 * allow menu-based category (class) selection (for Drop,take off etc.) 781 * 782 */ 783int 784query_category(qstr, olist, qflags, pick_list, how) 785const char *qstr; /* query string */ 786struct obj *olist; /* the list to pick from */ 787int qflags; /* behaviour modification flags */ 788menu_item **pick_list; /* return list of items picked */ 789int how; /* type of query */ 790{ 791 int n; 792 winid win; 793 struct obj *curr; 794 char *pack; 795 anything any; 796 boolean collected_type_name; 797 char invlet; 798 int ccount; 799 boolean do_unpaid = FALSE; 800 boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE, 801 do_buc_unknown = FALSE; 802 int num_buc_types = 0; 803 804 *pick_list = (menu_item *) 0; 805 if (!olist) return 0; 806 if ((qflags & UNPAID_TYPES) && count_unpaid(olist)) do_unpaid = TRUE; 807 if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) { 808 do_blessed = TRUE; 809 num_buc_types++; 810 } 811 if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) { 812 do_cursed = TRUE; 813 num_buc_types++; 814 } 815 if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) { 816 do_uncursed = TRUE; 817 num_buc_types++; 818 } 819 if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) { 820 do_buc_unknown = TRUE; 821 num_buc_types++; 822 } 823 824 ccount = count_categories(olist, qflags); 825 /* no point in actually showing a menu for a single category */ 826 if (ccount == 1 && !do_unpaid && num_buc_types <= 1 && !(qflags & BILLED_TYPES)) { 827 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { 828 if ((qflags & WORN_TYPES) && 829 !(curr->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL|W_WEP|W_SWAPWEP|W_QUIVER))) 830 continue; 831 break; 832 } 833 if (curr) { 834 *pick_list = (menu_item *) alloc(sizeof(menu_item)); 835 (*pick_list)->item.a_int = curr->oclass; 836 return 1; 837 } else { 838#ifdef NETHACK_DEBUG 839 impossible("query_category: no single object match"); 840#endif 841 } 842 return 0; 843 } 844 845 win = create_nhwindow(NHW_MENU); 846 start_menu(win); 847 pack = flags.inv_order; 848 if ((qflags & ALL_TYPES) && (ccount > 1)) { 849 invlet = 'a'; 850 any.a_void = 0; 851 any.a_int = ALL_TYPES_SELECTED; 852 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 853 (qflags & WORN_TYPES) ? "All worn types" : "All types", 854 MENU_UNSELECTED); 855 invlet = 'b'; 856 } else 857 invlet = 'a'; 858 do { 859 collected_type_name = FALSE; 860 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { 861 if (curr->oclass == *pack) { 862 if ((qflags & WORN_TYPES) && 863 !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | 864 W_WEP | W_SWAPWEP | W_QUIVER))) 865 continue; 866 if (!collected_type_name) { 867 any.a_void = 0; 868 any.a_int = curr->oclass; 869 add_menu(win, NO_GLYPH, &any, invlet++, 870 def_oc_syms[(int)objects[curr->otyp].oc_class], 871 ATR_NONE, let_to_name(*pack, FALSE), 872 MENU_UNSELECTED); 873 collected_type_name = TRUE; 874 } 875 } 876 } 877 pack++; 878 if (invlet >= 'u') { 879 impossible("query_category: too many categories"); 880 return 0; 881 } 882 } while (*pack); 883 /* unpaid items if there are any */ 884 if (do_unpaid) { 885 invlet = 'u'; 886 any.a_void = 0; 887 any.a_int = 'u'; 888 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 889 "Unpaid items", MENU_UNSELECTED); 890 } 891 /* billed items: checked by caller, so always include if BILLED_TYPES */ 892 if (qflags & BILLED_TYPES) { 893 invlet = 'x'; 894 any.a_void = 0; 895 any.a_int = 'x'; 896 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 897 "Unpaid items already used up", MENU_UNSELECTED); 898 } 899 if (qflags & CHOOSE_ALL) { 900 invlet = 'A'; 901 any.a_void = 0; 902 any.a_int = 'A'; 903 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 904 (qflags & WORN_TYPES) ? 905 "Auto-select every item being worn" : 906 "Auto-select every item", MENU_UNSELECTED); 907 } 908 /* items with b/u/c/unknown if there are any */ 909 if (do_blessed) { 910 invlet = 'B'; 911 any.a_void = 0; 912 any.a_int = 'B'; 913 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 914 "Items known to be Blessed", MENU_UNSELECTED); 915 } 916 if (do_cursed) { 917 invlet = 'C'; 918 any.a_void = 0; 919 any.a_int = 'C'; 920 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 921 "Items known to be Cursed", MENU_UNSELECTED); 922 } 923 if (do_uncursed) { 924 invlet = 'U'; 925 any.a_void = 0; 926 any.a_int = 'U'; 927 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 928 "Items known to be Uncursed", MENU_UNSELECTED); 929 } 930 if (do_buc_unknown) { 931 invlet = 'X'; 932 any.a_void = 0; 933 any.a_int = 'X'; 934 add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, 935 "Items of unknown B/C/U status", 936 MENU_UNSELECTED); 937 } 938 end_menu(win, qstr); 939 n = select_menu(win, how, pick_list); 940 destroy_nhwindow(win); 941 if (n < 0) 942 n = 0; /* caller's don't expect -1 */ 943 return n; 944} 945 946STATIC_OVL int 947count_categories(olist, qflags) 948struct obj *olist; 949int qflags; 950{ 951 char *pack; 952 boolean counted_category; 953 int ccount = 0; 954 struct obj *curr; 955 956 pack = flags.inv_order; 957 do { 958 counted_category = FALSE; 959 for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { 960 if (curr->oclass == *pack) { 961 if ((qflags & WORN_TYPES) && 962 !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | 963 W_WEP | W_SWAPWEP | W_QUIVER))) 964 continue; 965 if (!counted_category) { 966 ccount++; 967 counted_category = TRUE; 968 } 969 } 970 } 971 pack++; 972 } while (*pack); 973 return ccount; 974} 975 976/* could we carry `obj'? if not, could we carry some of it/them? */ 977STATIC_OVL long 978carry_count(obj, container, count, telekinesis, wt_before, wt_after) 979struct obj *obj, *container; /* object to pick up, bag it's coming out of */ 980long count; 981boolean telekinesis; 982int *wt_before, *wt_after; 983{ 984 boolean adjust_wt = container && carried(container), 985 is_gold = obj->oclass == COIN_CLASS; 986 int wt, iw, ow, oow; 987 long qq, savequan; 988#ifdef GOLDOBJ 989 long umoney = money_cnt(invent); 990#endif 991 unsigned saveowt; 992 const char *verb, *prefx1, *prefx2, *suffx; 993 char obj_nambuf[BUFSZ], where[BUFSZ]; 994 995 savequan = obj->quan; 996 saveowt = obj->owt; 997 998 iw = max_capacity(); 999 1000 if (count != savequan) { 1001 obj->quan = count; 1002 obj->owt = (unsigned)weight(obj); 1003 } 1004 wt = iw + (int)obj->owt; 1005 if (adjust_wt) 1006 wt -= (container->otyp == BAG_OF_HOLDING) ? 1007 (int)DELTA_CWT(container, obj) : (int)obj->owt; 1008#ifndef GOLDOBJ 1009 if (is_gold) /* merged gold might affect cumulative weight */ 1010 wt -= (GOLD_WT(u.ugold) + GOLD_WT(count) - GOLD_WT(u.ugold + count)); 1011#else 1012 /* This will go with silver+copper & new gold weight */ 1013 if (is_gold) /* merged gold might affect cumulative weight */ 1014 wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count)); 1015#endif 1016 if (count != savequan) { 1017 obj->quan = savequan; 1018 obj->owt = saveowt; 1019 } 1020 *wt_before = iw; 1021 *wt_after = wt; 1022 1023 if (wt < 0) 1024 return count; 1025 1026 /* see how many we can lift */ 1027 if (is_gold) { 1028#ifndef GOLDOBJ 1029 iw -= (int)GOLD_WT(u.ugold); 1030 if (!adjust_wt) { 1031 qq = GOLD_CAPACITY((long)iw, u.ugold); 1032 } else { 1033 oow = 0; 1034 qq = 50L - (u.ugold % 100L) - 1L; 1035#else 1036 iw -= (int)GOLD_WT(umoney); 1037 if (!adjust_wt) { 1038 qq = GOLD_CAPACITY((long)iw, umoney); 1039 } else { 1040 oow = 0; 1041 qq = 50L - (umoney % 100L) - 1L; 1042#endif 1043 if (qq < 0L) qq += 100L; 1044 for ( ; qq <= count; qq += 100L) { 1045 obj->quan = qq; 1046 obj->owt = (unsigned)GOLD_WT(qq); 1047#ifndef GOLDOBJ 1048 ow = (int)GOLD_WT(u.ugold + qq); 1049#else 1050 ow = (int)GOLD_WT(umoney + qq); 1051#endif 1052 ow -= (container->otyp == BAG_OF_HOLDING) ? 1053 (int)DELTA_CWT(container, obj) : (int)obj->owt; 1054 if (iw + ow >= 0) break; 1055 oow = ow; 1056 } 1057 iw -= oow; 1058 qq -= 100L; 1059 } 1060 if (qq < 0L) qq = 0L; 1061 else if (qq > count) qq = count; 1062#ifndef GOLDOBJ 1063 wt = iw + (int)GOLD_WT(u.ugold + qq); 1064#else 1065 wt = iw + (int)GOLD_WT(umoney + qq); 1066#endif 1067 } else if (count > 1 || count < obj->quan) { 1068 /* 1069 * Ugh. Calc num to lift by changing the quan of of the 1070 * object and calling weight. 1071 * 1072 * This works for containers only because containers 1073 * don't merge. -dean 1074 */ 1075 for (qq = 1L; qq <= count; qq++) { 1076 obj->quan = qq; 1077 obj->owt = (unsigned)(ow = weight(obj)); 1078 if (adjust_wt) 1079 ow -= (container->otyp == BAG_OF_HOLDING) ? 1080 (int)DELTA_CWT(container, obj) : (int)obj->owt; 1081 if (iw + ow >= 0) 1082 break; 1083 wt = iw + ow; 1084 } 1085 --qq; 1086 } else { 1087 /* there's only one, and we can't lift it */ 1088 qq = 0L; 1089 } 1090 obj->quan = savequan; 1091 obj->owt = saveowt; 1092 1093 if (qq < count) { 1094 /* some message will be given */ 1095 Strcpy(obj_nambuf, doname(obj)); 1096 if (container) { 1097 Sprintf(where, "in %s", the(xname(container))); 1098 verb = "carry"; 1099 } else { 1100 Strcpy(where, "lying here"); 1101 verb = telekinesis ? "acquire" : "lift"; 1102 } 1103 } else { 1104 /* lint supppression */ 1105 *obj_nambuf = *where = '\0'; 1106 verb = ""; 1107 } 1108 /* we can carry qq of them */ 1109 if (qq > 0) { 1110 if (qq < count) 1111 You("can only %s %s of the %s %s.", 1112 verb, (qq == 1L) ? "one" : "some", obj_nambuf, where); 1113 *wt_after = wt; 1114 return qq; 1115 } 1116 1117 if (!container) Strcpy(where, "here"); /* slightly shorter form */ 1118#ifndef GOLDOBJ 1119 if (invent || u.ugold) { 1120#else 1121 if (invent || umoney) { 1122#endif 1123 prefx1 = "you cannot "; 1124 prefx2 = ""; 1125 suffx = " any more"; 1126 } else { 1127 prefx1 = (obj->quan == 1L) ? "it " : "even one "; 1128 prefx2 = "is too heavy for you to "; 1129 suffx = ""; 1130 } 1131 There("%s %s %s, but %s%s%s%s.", 1132 otense(obj, "are"), obj_nambuf, where, 1133 prefx1, prefx2, verb, suffx); 1134 1135 /* *wt_after = iw; */ 1136 return 0L; 1137} 1138 1139/* determine whether character is able and player is willing to carry `obj' */ 1140STATIC_OVL 1141int 1142lift_object(obj, container, cnt_p, telekinesis) 1143struct obj *obj, *container; /* object to pick up, bag it's coming out of */ 1144long *cnt_p; 1145boolean telekinesis; 1146{ 1147 int result, old_wt, new_wt, prev_encumbr, next_encumbr; 1148 1149 if (obj->otyp == BOULDER && In_sokoban(&u.uz)) { 1150 You("cannot get your %s around this %s.", 1151 body_part(HAND), xname(obj)); 1152 return -1; 1153 } 1154 if (obj->otyp == LOADSTONE || 1155 (obj->otyp == BOULDER && throws_rocks(youmonst.data))) 1156 return 1; /* lift regardless of current situation */ 1157 1158 *cnt_p = carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt); 1159 if (*cnt_p < 1L) { 1160 result = -1; /* nothing lifted */ 1161#ifndef GOLDOBJ 1162 } else if (obj->oclass != COIN_CLASS && inv_cnt() >= 52 && 1163 !merge_choice(invent, obj)) { 1164#else 1165 } else if (inv_cnt() >= 52 && !merge_choice(invent, obj)) { 1166#endif 1167 Your("knapsack cannot accommodate any more items."); 1168 result = -1; /* nothing lifted */ 1169 } else { 1170 result = 1; 1171 prev_encumbr = near_capacity(); 1172 if (prev_encumbr < flags.pickup_burden) 1173 prev_encumbr = flags.pickup_burden; 1174 next_encumbr = calc_capacity(new_wt - old_wt); 1175 if (next_encumbr > prev_encumbr) { 1176 if (telekinesis) { 1177 result = 0; /* don't lift */ 1178 } else { 1179 char qbuf[BUFSZ]; 1180 long savequan = obj->quan; 1181 1182 obj->quan = *cnt_p; 1183 Strcpy(qbuf, 1184 (next_encumbr > HVY_ENCUMBER) ? overloadmsg : 1185 (next_encumbr > MOD_ENCUMBER) ? nearloadmsg : 1186 moderateloadmsg); 1187 Sprintf(eos(qbuf), " %s. Continue?", 1188 safe_qbuf(qbuf, sizeof(" . Continue?"), 1189 doname(obj), an(simple_typename(obj->otyp)), "something")); 1190 obj->quan = savequan; 1191 switch (ynq(qbuf)) { 1192 case 'q': result = -1; break; 1193 case 'n': result = 0; break; 1194 default: break; /* 'y' => result == 1 */ 1195 } 1196 clear_nhwindow(WIN_MESSAGE); 1197 } 1198 } 1199 } 1200 1201 if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container) 1202 obj->spe = 0; 1203 return result; 1204} 1205 1206/* To prevent qbuf overflow in prompts use planA only 1207 * if it fits, or planB if PlanA doesn't fit, 1208 * finally using the fallback as a last resort. 1209 * last_restort is expected to be very short. 1210 */ 1211const char * 1212safe_qbuf(qbuf, padlength, planA, planB, last_resort) 1213const char *qbuf, *planA, *planB, *last_resort; 1214unsigned padlength; 1215{ 1216 /* convert size_t (or int for ancient systems) to ordinary unsigned */ 1217 unsigned len_qbuf = (unsigned)strlen(qbuf), 1218 len_planA = (unsigned)strlen(planA), 1219 len_planB = (unsigned)strlen(planB), 1220 len_lastR = (unsigned)strlen(last_resort); 1221 unsigned textleft = QBUFSZ - (len_qbuf + padlength); 1222 1223 if (len_lastR >= textleft) { 1224 impossible("safe_qbuf: last_resort too large at %u characters.", 1225 len_lastR); 1226 return ""; 1227 } 1228 return (len_planA < textleft) ? planA : 1229 (len_planB < textleft) ? planB : last_resort; 1230} 1231 1232/* 1233 * Pick up <count> of obj from the ground and add it to the hero's inventory. 1234 * Returns -1 if caller should break out of its loop, 0 if nothing picked 1235 * up, 1 if otherwise. 1236 */ 1237int 1238pickup_object(obj, count, telekinesis) 1239struct obj *obj; 1240long count; 1241boolean telekinesis; /* not picking it up directly by hand */ 1242{ 1243 int res, nearload; 1244#ifndef GOLDOBJ 1245 const char *where = (obj->ox == u.ux && obj->oy == u.uy) ? 1246 "here" : "there"; 1247#endif 1248 1249 if (obj->quan < count) { 1250 impossible("pickup_object: count %ld > quan %ld?", 1251 count, obj->quan); 1252 return 0; 1253 } 1254 1255 /* In case of auto-pickup, where we haven't had a chance 1256 to look at it yet; affects docall(SCR_SCARE_MONSTER). */ 1257 if (!Blind) 1258#ifdef INVISIBLE_OBJECTS 1259 if (!obj->oinvis || See_invisible) 1260#endif 1261 obj->dknown = 1; 1262 1263 if (obj == uchain) { /* do not pick up attached chain */ 1264 return 0; 1265 } else if (obj->oartifact && !touch_artifact(obj,&youmonst)) { 1266 return 0; 1267#ifndef GOLDOBJ 1268 } else if (obj->oclass == COIN_CLASS) { 1269 /* Special consideration for gold pieces... */ 1270 long iw = (long)max_capacity() - GOLD_WT(u.ugold); 1271 long gold_capacity = GOLD_CAPACITY(iw, u.ugold); 1272 1273 if (gold_capacity <= 0L) { 1274 pline( 1275 "There %s %ld gold piece%s %s, but you cannot carry any more.", 1276 otense(obj, "are"), 1277 obj->quan, plur(obj->quan), where); 1278 return 0; 1279 } else if (gold_capacity < count) { 1280 You("can only %s %s of the %ld gold pieces lying %s.", 1281 telekinesis ? "acquire" : "carry", 1282 gold_capacity == 1L ? "one" : "some", obj->quan, where); 1283 pline("%s %ld gold piece%s.", 1284 nearloadmsg, gold_capacity, plur(gold_capacity)); 1285 u.ugold += gold_capacity; 1286 obj->quan -= gold_capacity; 1287 costly_gold(obj->ox, obj->oy, gold_capacity); 1288 } else { 1289 u.ugold += count; 1290 if ((nearload = near_capacity()) != 0) 1291 pline("%s %ld gold piece%s.", 1292 nearload < MOD_ENCUMBER ? 1293 moderateloadmsg : nearloadmsg, 1294 count, plur(count)); 1295 else 1296 prinv((char *) 0, obj, count); 1297 costly_gold(obj->ox, obj->oy, count); 1298 if (count == obj->quan) 1299 delobj(obj); 1300 else 1301 obj->quan -= count; 1302 } 1303 flags.botl = 1; 1304 if (flags.run) nomul(0); 1305 return 1; 1306#endif 1307 } else if (obj->otyp == CORPSE) { 1308 if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg 1309 && !Stone_resistance && !telekinesis) { 1310 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) 1311 display_nhwindow(WIN_MESSAGE, FALSE); 1312 else { 1313 char kbuf[BUFSZ]; 1314 1315 Strcpy(kbuf, an(corpse_xname(obj, TRUE))); 1316 pline("Touching %s is a fatal mistake.", kbuf); 1317 instapetrify(kbuf); 1318 return -1; 1319 } 1320 } else if (is_rider(&mons[obj->corpsenm])) { 1321 pline("At your %s, the corpse suddenly moves...", 1322 telekinesis ? "attempted acquisition" : "touch"); 1323 (void) revive_corpse(obj); 1324 exercise(A_WIS, FALSE); 1325 return -1; 1326 } 1327 } else if (obj->otyp == SCR_SCARE_MONSTER) { 1328 if (obj->blessed) obj->blessed = 0; 1329 else if (!obj->spe && !obj->cursed) obj->spe = 1; 1330 else { 1331 pline_The("scroll%s %s to dust as you %s %s up.", 1332 plur(obj->quan), otense(obj, "turn"), 1333 telekinesis ? "raise" : "pick", 1334 (obj->quan == 1L) ? "it" : "them"); 1335 if (!(objects[SCR_SCARE_MONSTER].oc_name_known) && 1336 !(objects[SCR_SCARE_MONSTER].oc_uname)) 1337 docall(obj); 1338 useupf(obj, obj->quan); 1339 return 1; /* tried to pick something up and failed, but 1340 don't want to terminate pickup loop yet */ 1341 } 1342 } 1343 1344 if ((res = lift_object(obj, (struct obj *)0, &count, telekinesis)) <= 0) 1345 return res; 1346 1347#ifdef GOLDOBJ 1348 /* Whats left of the special case for gold :-) */ 1349 if (obj->oclass == COIN_CLASS) flags.botl = 1; 1350#endif 1351 if (obj->quan != count && obj->otyp != LOADSTONE) 1352 obj = splitobj(obj, count); 1353 1354 obj = pick_obj(obj); 1355 1356 if (uwep && uwep == obj) mrg_to_wielded = TRUE; 1357 nearload = near_capacity(); 1358 prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0, 1359 obj, count); 1360 mrg_to_wielded = FALSE; 1361 return 1; 1362} 1363 1364/* 1365 * Do the actual work of picking otmp from the floor or monster's interior 1366 * and putting it in the hero's inventory. Take care of billing. Return a 1367 * pointer to the object where otmp ends up. This may be different 1368 * from otmp because of merging. 1369 * 1370 * Gold never reaches this routine unless GOLDOBJ is defined. 1371 */ 1372struct obj * 1373pick_obj(otmp) 1374struct obj *otmp; 1375{ 1376 obj_extract_self(otmp); 1377 if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) { 1378 char saveushops[5], fakeshop[2]; 1379 1380 /* addtobill cares about your location rather than the object's; 1381 usually they'll be the same, but not when using telekinesis 1382 (if ever implemented) or a grappling hook */ 1383 Strcpy(saveushops, u.ushops); 1384 fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE); 1385 fakeshop[1] = '\0'; 1386 Strcpy(u.ushops, fakeshop); 1387 /* sets obj->unpaid if necessary */ 1388 addtobill(otmp, TRUE, FALSE, FALSE); 1389 Strcpy(u.ushops, saveushops); 1390 /* if you're outside the shop, make shk notice */ 1391 if (!index(u.ushops, *fakeshop)) 1392 remote_burglary(otmp->ox, otmp->oy); 1393 } 1394 if (otmp->no_charge) /* only applies to objects outside invent */ 1395 otmp->no_charge = 0; 1396 newsym(otmp->ox, otmp->oy); 1397 return addinv(otmp); /* might merge it with other objects */ 1398} 1399 1400/* 1401 * prints a message if encumbrance changed since the last check and 1402 * returns the new encumbrance value (from near_capacity()). 1403 */ 1404int 1405encumber_msg() 1406{ 1407 static int oldcap = UNENCUMBERED; 1408 int newcap = near_capacity(); 1409 1410 if(oldcap < newcap) { 1411 switch(newcap) { 1412 case 1: Your("movements are slowed slightly because of your load."); 1413 break; 1414 case 2: You("rebalance your load. Movement is difficult."); 1415 break; 1416 case 3: You("%s under your heavy load. Movement is very hard.", 1417 stagger(youmonst.data, "stagger")); 1418 break; 1419 default: You("%s move a handspan with this load!", 1420 newcap == 4 ? "can barely" : "can't even"); 1421 break; 1422 } 1423 flags.botl = 1; 1424 } else if(oldcap > newcap) { 1425 switch(newcap) { 1426 case 0: Your("movements are now unencumbered."); 1427 break; 1428 case 1: Your("movements are only slowed slightly by your load."); 1429 break; 1430 case 2: You("rebalance your load. Movement is still difficult."); 1431 break; 1432 case 3: You("%s under your load. Movement is still very hard.", 1433 stagger(youmonst.data, "stagger")); 1434 break; 1435 } 1436 flags.botl = 1; 1437 } 1438 1439 oldcap = newcap; 1440 return (newcap); 1441} 1442 1443/* Is there a container at x,y. Optional: return count of containers at x,y */ 1444STATIC_OVL int 1445container_at(x, y, countem) 1446int x,y; 1447boolean countem; 1448{ 1449 struct obj *cobj, *nobj; 1450 int container_count = 0; 1451 1452 for(cobj = level.objects[x][y]; cobj; cobj = nobj) { 1453 nobj = cobj->nexthere; 1454 if(Is_container(cobj)) { 1455 container_count++; 1456 if (!countem) break; 1457 } 1458 } 1459 return container_count; 1460} 1461 1462STATIC_OVL boolean 1463able_to_loot(x, y) 1464int x, y; 1465{ 1466 if (!can_reach_floor()) { 1467#ifdef STEED 1468 if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) 1469 rider_cant_reach(); /* not skilled enough to reach */ 1470 else 1471#endif 1472 You("cannot reach the %s.", surface(x, y)); 1473 return FALSE; 1474 } else if (is_pool(x, y) || is_lava(x, y)) { 1475 /* at present, can't loot in water even when Underwater */ 1476 You("cannot loot things that are deep in the %s.", 1477 is_lava(x, y) ? "lava" : "water"); 1478 return FALSE; 1479 } else if (nolimbs(youmonst.data)) { 1480 pline("Without limbs, you cannot loot anything."); 1481 return FALSE; 1482 } else if (!freehand()) { 1483 pline("Without a free %s, you cannot loot anything.", 1484 body_part(HAND)); 1485 return FALSE; 1486 } 1487 return TRUE; 1488} 1489 1490STATIC_OVL boolean 1491mon_beside(x,y) 1492int x, y; 1493{ 1494 int i,j,nx,ny; 1495 for(i = -1; i <= 1; i++) 1496 for(j = -1; j <= 1; j++) { 1497 nx = x + i; 1498 ny = y + j; 1499 if(isok(nx, ny) && MON_AT(nx, ny)) 1500 return TRUE; 1501 } 1502 return FALSE; 1503} 1504 1505int 1506doloot() /* loot a container on the floor or loot saddle from mon. */ 1507{ 1508 register struct obj *cobj, *nobj; 1509 register int c = -1; 1510 int timepassed = 0; 1511 coord cc; 1512 boolean underfoot = TRUE; 1513 const char *dont_find_anything = "don't find anything"; 1514 struct monst *mtmp; 1515 char qbuf[BUFSZ]; 1516 int prev_inquiry = 0; 1517 boolean prev_loot = FALSE; 1518 1519 if (check_capacity((char *)0)) { 1520 /* "Can't do that while carrying so much stuff." */ 1521 return 0; 1522 } 1523 if (nohands(youmonst.data)) { 1524 You("have no hands!"); /* not `body_part(HAND)' */ 1525 return 0; 1526 } 1527 cc.x = u.ux; cc.y = u.uy; 1528 1529lootcont: 1530 1531 if (container_at(cc.x, cc.y, FALSE)) { 1532 boolean any = FALSE; 1533 1534 if (!able_to_loot(cc.x, cc.y)) return 0; 1535 for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { 1536 nobj = cobj->nexthere; 1537 1538 if (Is_container(cobj)) { 1539 Sprintf(qbuf, "There is %s here, loot it?", 1540 safe_qbuf("", sizeof("There is here, loot it?"), 1541 doname(cobj), an(simple_typename(cobj->otyp)), 1542 "a container")); 1543 c = ynq(qbuf); 1544 if (c == 'q') return (timepassed); 1545 if (c == 'n') continue; 1546 any = TRUE; 1547 1548 if (cobj->olocked) { 1549 pline("Hmmm, it seems to be locked."); 1550 continue; 1551 } 1552 if (cobj->otyp == BAG_OF_TRICKS) { 1553 int tmp; 1554 You("carefully open the bag..."); 1555 pline("It develops a huge set of teeth and bites you!"); 1556 tmp = rnd(10); 1557 if (Half_physical_damage) tmp = (tmp+1) / 2; 1558 losehp(tmp, "carnivorous bag", KILLED_BY_AN); 1559 makeknown(BAG_OF_TRICKS); 1560 timepassed = 1; 1561 continue; 1562 } 1563 1564 You("carefully open %s...", the(xname(cobj))); 1565 timepassed |= use_container(cobj, 0); 1566 if (multi < 0) return 1; /* chest trap */ 1567 } 1568 } 1569 if (any) c = 'y'; 1570 } else if (Confusion) { 1571#ifndef GOLDOBJ 1572 if (u.ugold){ 1573 long contribution = rnd((int)min(LARGEST_INT,u.ugold)); 1574 struct obj *goldob = mkgoldobj(contribution); 1575#else 1576 struct obj *goldob; 1577 /* Find a money object to mess with */ 1578 for (goldob = invent; goldob; goldob = goldob->nobj) { 1579 if (goldob->oclass == COIN_CLASS) break; 1580 } 1581 if (goldob){ 1582 long contribution = rnd((int)min(LARGEST_INT, goldob->quan)); 1583 if (contribution < goldob->quan) 1584 goldob = splitobj(goldob, contribution); 1585 freeinv(goldob); 1586#endif 1587 if (IS_THRONE(levl[u.ux][u.uy].typ)){ 1588 struct obj *coffers; 1589 int pass; 1590 /* find the original coffers chest, or any chest */ 1591 for (pass = 2; pass > -1; pass -= 2) 1592 for (coffers = fobj; coffers; coffers = coffers->nobj) 1593 if (coffers->otyp == CHEST && coffers->spe == pass) 1594 goto gotit; /* two level break */ 1595gotit: 1596 if (coffers) { 1597 verbalize("Thank you for your contribution to reduce the debt."); 1598 (void) add_to_container(coffers, goldob); 1599 coffers->owt = weight(coffers); 1600 } else { 1601 struct monst *mon = makemon(courtmon(), 1602 u.ux, u.uy, NO_MM_FLAGS); 1603 if (mon) { 1604#ifndef GOLDOBJ 1605 mon->mgold += goldob->quan; 1606 delobj(goldob); 1607 pline("The exchequer accepts your contribution."); 1608 } else { 1609 dropx(goldob); 1610 } 1611 } 1612 } else { 1613 dropx(goldob); 1614#else 1615 add_to_minv(mon, goldob); 1616 pline("The exchequer accepts your contribution."); 1617 } else { 1618 dropy(goldob); 1619 } 1620 } 1621 } else { 1622 dropy(goldob); 1623#endif 1624 pline("Ok, now there is loot here."); 1625 } 1626 } 1627 } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) { 1628 You("need to dig up the grave to effectively loot it..."); 1629 } 1630 /* 1631 * 3.3.1 introduced directional looting for some things. 1632 */ 1633 if (c != 'y' && mon_beside(u.ux, u.uy)) { 1634 if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location", 1635 u.ux, u.uy, &cc)) return 0; 1636 if (cc.x == u.ux && cc.y == u.uy) { 1637 underfoot = TRUE; 1638 if (container_at(cc.x, cc.y, FALSE)) 1639 goto lootcont; 1640 } else 1641 underfoot = FALSE; 1642 if (u.dz < 0) { 1643 You("%s to loot on the %s.", dont_find_anything, 1644 ceiling(cc.x, cc.y)); 1645 timepassed = 1; 1646 return timepassed; 1647 } 1648 mtmp = m_at(cc.x, cc.y); 1649 if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot); 1650 1651 /* Preserve pre-3.3.1 behaviour for containers. 1652 * Adjust this if-block to allow container looting 1653 * from one square away to change that in the future. 1654 */ 1655 if (!underfoot) { 1656 if (container_at(cc.x, cc.y, FALSE)) { 1657 if (mtmp) { 1658 You_cant("loot anything %sthere with %s in the way.", 1659 prev_inquiry ? "else " : "", mon_nam(mtmp)); 1660 return timepassed; 1661 } else { 1662 You("have to be at a container to loot it."); 1663 } 1664 } else { 1665 You("%s %sthere to loot.", dont_find_anything, 1666 (prev_inquiry || prev_loot) ? "else " : ""); 1667 return timepassed; 1668 } 1669 } 1670 } else if (c != 'y' && c != 'n') { 1671 You("%s %s to loot.", dont_find_anything, 1672 underfoot ? "here" : "there"); 1673 } 1674 return (timepassed); 1675} 1676 1677/* loot_mon() returns amount of time passed. 1678 */ 1679int 1680loot_mon(mtmp, passed_info, prev_loot) 1681struct monst *mtmp; 1682int *passed_info; 1683boolean *prev_loot; 1684{ 1685 int c = -1; 1686 int timepassed = 0; 1687#ifdef STEED 1688 struct obj *otmp; 1689 char qbuf[QBUFSZ]; 1690 1691 /* 3.3.1 introduced the ability to remove saddle from a steed */ 1692 /* *passed_info is set to TRUE if a loot query was given. */ 1693 /* *prev_loot is set to TRUE if something was actually acquired in here. */ 1694 if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) { 1695 long unwornmask; 1696 if (passed_info) *passed_info = 1; 1697 Sprintf(qbuf, "Do you want to remove the saddle from %s?", 1698 x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE)); 1699 if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { 1700 if (nolimbs(youmonst.data)) { 1701 You_cant("do that without limbs."); /* not body_part(HAND) */ 1702 return (0); 1703 } 1704 if (otmp->cursed) { 1705 You("can't. The saddle seems to be stuck to %s.", 1706 x_monnam(mtmp, ARTICLE_THE, (char *)0, 1707 SUPPRESS_SADDLE, FALSE)); 1708 1709 /* the attempt costs you time */ 1710 return (1); 1711 } 1712 obj_extract_self(otmp); 1713 if ((unwornmask = otmp->owornmask) != 0L) { 1714 mtmp->misc_worn_check &= ~unwornmask; 1715 otmp->owornmask = 0L; 1716 update_mon_intrinsics(mtmp, otmp, FALSE, FALSE); 1717 } 1718 otmp = hold_another_object(otmp, "You drop %s!", doname(otmp), 1719 (const char *)0); 1720 timepassed = rnd(3); 1721 if (prev_loot) *prev_loot = TRUE; 1722 } else if (c == 'q') { 1723 return (0); 1724 } 1725 } 1726#endif /* STEED */ 1727 /* 3.4.0 introduced the ability to pick things up from within swallower's stomach */ 1728 if (u.uswallow) { 1729 int count = passed_info ? *passed_info : 0; 1730 timepassed = pickup(count); 1731 } 1732 return timepassed; 1733} 1734 1735/* 1736 * Decide whether an object being placed into a magic bag will cause 1737 * it to explode. If the object is a bag itself, check recursively. 1738 */ 1739STATIC_OVL boolean 1740mbag_explodes(obj, depthin) 1741 struct obj *obj; 1742 int depthin; 1743{ 1744 /* these won't cause an explosion when they're empty */ 1745 if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS) && 1746 obj->spe <= 0) 1747 return FALSE; 1748 1749 /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */ 1750 if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION) && 1751 (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin)) 1752 return TRUE; 1753 else if (Has_contents(obj)) { 1754 struct obj *otmp; 1755 1756 for (otmp = obj->cobj; otmp; otmp = otmp->nobj) 1757 if (mbag_explodes(otmp, depthin+1)) return TRUE; 1758 } 1759 return FALSE; 1760} 1761 1762/* A variable set in use_container(), to be used by the callback routines */ 1763/* in_container(), and out_container() from askchain() and use_container(). */ 1764static NEARDATA struct obj *current_container; 1765#define Icebox (current_container->otyp == ICE_BOX) 1766 1767/* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */ 1768STATIC_PTR int 1769in_container(obj) 1770register struct obj *obj; 1771{ 1772 boolean floor_container = !carried(current_container); 1773 boolean was_unpaid = FALSE; 1774 char buf[BUFSZ]; 1775 1776 if (!current_container) { 1777 impossible("<in> no current_container?"); 1778 return 0; 1779 } else if (obj == uball || obj == uchain) { 1780 You("must be kidding."); 1781 return 0; 1782 } else if (obj == current_container) { 1783 pline("That would be an interesting topological exercise."); 1784 return 0; 1785 } else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) { 1786 Norep("You cannot %s %s you are wearing.", 1787 Icebox ? "refrigerate" : "stash", something); 1788 return 0; 1789 } else if ((obj->otyp == LOADSTONE) && obj->cursed) { 1790 obj->bknown = 1; 1791 pline_The("stone%s won't leave your person.", plur(obj->quan)); 1792 return 0; 1793 } else if (obj->otyp == AMULET_OF_YENDOR || 1794 obj->otyp == CANDELABRUM_OF_INVOCATION || 1795 obj->otyp == BELL_OF_OPENING || 1796 obj->otyp == SPE_BOOK_OF_THE_DEAD) { 1797 /* Prohibit Amulets in containers; if you allow it, monsters can't 1798 * steal them. It also becomes a pain to check to see if someone 1799 * has the Amulet. Ditto for the Candelabrum, the Bell and the Book. 1800 */ 1801 pline("%s cannot be confined in such trappings.", The(xname(obj))); 1802 return 0; 1803 } else if (obj->otyp == LEASH && obj->leashmon != 0) { 1804 pline("%s attached to your pet.", Tobjnam(obj, "are")); 1805 return 0; 1806 } else if (obj == uwep) { 1807 if (welded(obj)) { 1808 weldmsg(obj); 1809 return 0; 1810 } 1811 setuwep((struct obj *) 0); 1812 if (uwep) return 0; /* unwielded, died, rewielded */ 1813 } else if (obj == uswapwep) { 1814 setuswapwep((struct obj *) 0); 1815 if (uswapwep) return 0; /* unwielded, died, rewielded */ 1816 } else if (obj == uquiver) { 1817 setuqwep((struct obj *) 0); 1818 if (uquiver) return 0; /* unwielded, died, rewielded */ 1819 } 1820 1821 if (obj->otyp == CORPSE) { 1822 if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg 1823 && !Stone_resistance) { 1824 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) 1825 display_nhwindow(WIN_MESSAGE, FALSE); 1826 else { 1827 char kbuf[BUFSZ]; 1828 1829 Strcpy(kbuf, an(corpse_xname(obj, TRUE))); 1830 pline("Touching %s is a fatal mistake.", kbuf); 1831 instapetrify(kbuf); 1832 return -1; 1833 } 1834 } 1835 } 1836 1837 /* boxes, boulders, and big statues can't fit into any container */ 1838 if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER || 1839 (obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) { 1840 /* 1841 * xname() uses a static result array. Save obj's name 1842 * before current_container's name is computed. Don't 1843 * use the result of strcpy() within You() --- the order 1844 * of evaluation of the parameters is undefined. 1845 */ 1846 Strcpy(buf, the(xname(obj))); 1847 You("cannot fit %s into %s.", buf, 1848 the(xname(current_container))); 1849 return 0; 1850 } 1851 1852 freeinv(obj); 1853 1854 if (obj_is_burning(obj)) /* this used to be part of freeinv() */ 1855 (void) snuff_lit(obj); 1856 1857 if (floor_container && costly_spot(u.ux, u.uy)) { 1858 if (current_container->no_charge && !obj->unpaid) { 1859 /* don't sell when putting the item into your own container */ 1860 obj->no_charge = 1; 1861 } else if (obj->oclass != COIN_CLASS) { 1862 /* sellobj() will take an unpaid item off the shop bill 1863 * note: coins are handled later */ 1864 was_unpaid = obj->unpaid ? TRUE : FALSE; 1865 sellobj_state(SELL_DELIBERATE); 1866 sellobj(obj, u.ux, u.uy); 1867 sellobj_state(SELL_NORMAL); 1868 } 1869 } 1870 if (Icebox && !age_is_relative(obj)) { 1871 obj->age = monstermoves - obj->age; /* actual age */ 1872 /* stop any corpse timeouts when frozen */ 1873 if (obj->otyp == CORPSE && obj->timed) { 1874 long rot_alarm = stop_timer(ROT_CORPSE, (genericptr_t)obj); 1875 (void) stop_timer(REVIVE_MON, (genericptr_t)obj); 1876 /* mark a non-reviving corpse as such */ 1877 if (rot_alarm) obj->norevive = 1; 1878 } 1879 } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) { 1880 /* explicitly mention what item is triggering the explosion */ 1881 pline( 1882 "As you put %s inside, you are blasted by a magical explosion!", 1883 doname(obj)); 1884 /* did not actually insert obj yet */ 1885 if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE); 1886 obfree(obj, (struct obj *)0); 1887 delete_contents(current_container); 1888 if (!floor_container) 1889 useup(current_container); 1890 else if (obj_here(current_container, u.ux, u.uy)) 1891 useupf(current_container, obj->quan); 1892 else 1893 panic("in_container: bag not found."); 1894 1895 losehp(d(6,6),"magical explosion", KILLED_BY_AN); 1896 current_container = 0; /* baggone = TRUE; */ 1897 } 1898 1899 if (current_container) { 1900 Strcpy(buf, the(xname(current_container))); 1901 You("put %s into %s.", doname(obj), buf); 1902 1903 /* gold in container always needs to be added to credit */ 1904 if (floor_container && obj->oclass == COIN_CLASS) 1905 sellobj(obj, current_container->ox, current_container->oy); 1906 (void) add_to_container(current_container, obj); 1907 current_container->owt = weight(current_container); 1908 } 1909 /* gold needs this, and freeinv() many lines above may cause 1910 * the encumbrance to disappear from the status, so just always 1911 * update status immediately. 1912 */ 1913 bot(); 1914 1915 return(current_container ? 1 : -1); 1916} 1917 1918STATIC_PTR int 1919ck_bag(obj) 1920struct obj *obj; 1921{ 1922 return current_container && obj != current_container; 1923} 1924 1925/* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */ 1926STATIC_PTR int 1927out_container(obj) 1928register struct obj *obj; 1929{ 1930 register struct obj *otmp; 1931 boolean is_gold = (obj->oclass == COIN_CLASS); 1932 int res, loadlev; 1933 long count; 1934 1935 if (!current_container) { 1936 impossible("<out> no current_container?"); 1937 return -1; 1938 } else if (is_gold) { 1939 obj->owt = weight(obj); 1940 } 1941 1942 if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0; 1943 1944 if (obj->otyp == CORPSE) { 1945 if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg 1946 && !Stone_resistance) { 1947 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) 1948 display_nhwindow(WIN_MESSAGE, FALSE); 1949 else { 1950 char kbuf[BUFSZ]; 1951 1952 Strcpy(kbuf, an(corpse_xname(obj, TRUE))); 1953 pline("Touching %s is a fatal mistake.", kbuf); 1954 instapetrify(kbuf); 1955 return -1; 1956 } 1957 } 1958 } 1959 1960 count = obj->quan; 1961 if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0) 1962 return res; 1963 1964 if (obj->quan != count && obj->otyp != LOADSTONE) 1965 obj = splitobj(obj, count); 1966 1967 /* Remove the object from the list. */ 1968 obj_extract_self(obj); 1969 current_container->owt = weight(current_container); 1970 1971 if (Icebox && !age_is_relative(obj)) { 1972 obj->age = monstermoves - obj->age; /* actual age */ 1973 if (obj->otyp == CORPSE) 1974 start_corpse_timeout(obj); 1975 } 1976 /* simulated point of time */ 1977 1978 if(!obj->unpaid && !carried(current_container) && 1979 costly_spot(current_container->ox, current_container->oy)) { 1980 obj->ox = current_container->ox; 1981 obj->oy = current_container->oy; 1982 addtobill(obj, FALSE, FALSE, FALSE); 1983 } 1984 if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops)) 1985 verbalize("You sneaky cad! Get out of here with that pick!"); 1986 1987 otmp = addinv(obj); 1988 loadlev = near_capacity(); 1989 prinv(loadlev ? 1990 (loadlev < MOD_ENCUMBER ? 1991 "You have a little trouble removing" : 1992 "You have much trouble removing") : (char *)0, 1993 otmp, count); 1994 1995 if (is_gold) { 1996#ifndef GOLDOBJ 1997 dealloc_obj(obj); 1998#endif 1999 bot(); /* update character's gold piece count immediately */ 2000 } 2001 return 1; 2002} 2003 2004/* an object inside a cursed bag of holding is being destroyed */ 2005STATIC_OVL long 2006mbag_item_gone(held, item) 2007int held; 2008struct obj *item; 2009{ 2010 struct monst *shkp; 2011 long loss = 0L; 2012 2013 if (item->dknown) 2014 pline("%s %s vanished!", Doname2(item), otense(item, "have")); 2015 else 2016 You("%s %s disappear!", Blind ? "notice" : "see", doname(item)); 2017 2018 if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) { 2019 if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy)) 2020 loss = stolen_value(item, u.ux, u.uy, 2021 (boolean)shkp->mpeaceful, TRUE); 2022 } 2023 obfree(item, (struct obj *) 0); 2024 return loss; 2025} 2026 2027STATIC_OVL void 2028observe_quantum_cat(box) 2029struct obj *box; 2030{ 2031 static NEARDATA const char sc[] = "Schroedinger's Cat"; 2032 struct obj *deadcat; 2033 struct monst *livecat; 2034 xchar ox, oy; 2035 2036 box->spe = 0; /* box->owt will be updated below */ 2037 if (get_obj_location(box, &ox, &oy, 0)) 2038 box->ox = ox, box->oy = oy; /* in case it's being carried */ 2039 2040 /* this isn't really right, since any form of observation 2041 (telepathic or monster/object/food detection) ought to 2042 force the determination of alive vs dead state; but basing 2043 it just on opening the box is much simpler to cope with */ 2044 livecat = rn2(2) ? makemon(&mons[PM_HOUSECAT], 2045 box->ox, box->oy, NO_MINVENT) : 0; 2046 if (livecat) { 2047 livecat->mpeaceful = 1; 2048 set_malign(livecat); 2049 if (!canspotmon(livecat)) 2050 You("think %s brushed your %s.", something, body_part(FOOT)); 2051 else 2052 pline("%s inside the box is still alive!", Monnam(livecat)); 2053 (void) christen_monst(livecat, sc); 2054 } else { 2055 deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT], 2056 box->ox, box->oy, sc); 2057 if (deadcat) { 2058 obj_extract_self(deadcat); 2059 (void) add_to_container(box, deadcat); 2060 } 2061 pline_The("%s inside the box is dead!", 2062 Hallucination ? rndmonnam() : "housecat"); 2063 } 2064 box->owt = weight(box); 2065 return; 2066} 2067 2068#undef Icebox 2069 2070int 2071use_container(obj, held) 2072register struct obj *obj; 2073register int held; 2074{ 2075 struct obj *curr, *otmp; 2076#ifndef GOLDOBJ 2077 struct obj *u_gold = (struct obj *)0; 2078#endif 2079 boolean one_by_one, allflag, quantum_cat = FALSE, 2080 loot_out = FALSE, loot_in = FALSE; 2081 char select[MAXOCLASSES+1]; 2082 char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ]; 2083 long loss = 0L; 2084 int cnt = 0, used = 0, 2085 menu_on_request; 2086 2087 emptymsg[0] = '\0'; 2088 if (nohands(youmonst.data)) { 2089 You("have no hands!"); /* not `body_part(HAND)' */ 2090 return 0; 2091 } else if (!freehand()) { 2092 You("have no free %s.", body_part(HAND)); 2093 return 0; 2094 } 2095 if (obj->olocked) { 2096 pline("%s to be locked.", Tobjnam(obj, "seem")); 2097 if (held) You("must put it down to unlock."); 2098 return 0; 2099 } else if (obj->otrapped) { 2100 if (held) You("open %s...", the(xname(obj))); 2101 (void) chest_trap(obj, HAND, FALSE); 2102 /* even if the trap fails, you've used up this turn */ 2103 if (multi >= 0) { /* in case we didn't become paralyzed */ 2104 nomul(-1); 2105 nomovemsg = ""; 2106 } 2107 return 1; 2108 } 2109 current_container = obj; /* for use by in/out_container */ 2110 2111 if (obj->spe == 1) { 2112 observe_quantum_cat(obj); 2113 used = 1; 2114 quantum_cat = TRUE; /* for adjusting "it's empty" message */ 2115 } 2116 /* Count the number of contained objects. Sometimes toss objects if */ 2117 /* a cursed magic bag. */ 2118 for (curr = obj->cobj; curr; curr = otmp) { 2119 otmp = curr->nobj; 2120 if (Is_mbag(obj) && obj->cursed && !rn2(13)) { 2121 obj_extract_self(curr); 2122 loss += mbag_item_gone(held, curr); 2123 used = 1; 2124 } else { 2125 cnt++; 2126 } 2127 } 2128 2129 if (loss) /* magic bag lost some shop goods */ 2130 You("owe %ld %s for lost merchandise.", loss, currency(loss)); 2131 obj->owt = weight(obj); /* in case any items were lost */ 2132 2133 if (!cnt) 2134 Sprintf(emptymsg, "%s is %sempty.", Yname2(obj), 2135 quantum_cat ? "now " : ""); 2136 2137 if (cnt || flags.menu_style == MENU_FULL) { 2138 Strcpy(qbuf, "Do you want to take something out of "); 2139 Sprintf(eos(qbuf), "%s?", 2140 safe_qbuf(qbuf, 1, yname(obj), ysimple_name(obj), "it")); 2141 if (flags.menu_style != MENU_TRADITIONAL) { 2142 if (flags.menu_style == MENU_FULL) { 2143 int t; 2144 char menuprompt[BUFSZ]; 2145 boolean outokay = (cnt != 0); 2146#ifndef GOLDOBJ 2147 boolean inokay = (invent != 0) || (u.ugold != 0); 2148#else 2149 boolean inokay = (invent != 0); 2150#endif 2151 if (!outokay && !inokay) { 2152 pline("%s", emptymsg); 2153 You("don't have anything to put in."); 2154 return used; 2155 } 2156 menuprompt[0] = '\0'; 2157 if (!cnt) Sprintf(menuprompt, "%s ", emptymsg); 2158 Strcat(menuprompt, "Do what?"); 2159 t = in_or_out_menu(menuprompt, current_container, outokay, inokay); 2160 if (t <= 0) return 0; 2161 loot_out = (t & 0x01) != 0; 2162 loot_in = (t & 0x02) != 0; 2163 } else { /* MENU_COMBINATION or MENU_PARTIAL */ 2164 loot_out = (yn_function(qbuf, "ynq", 'n') == 'y'); 2165 } 2166 if (loot_out) { 2167 add_valid_menu_class(0); /* reset */ 2168 used |= menu_loot(0, current_container, FALSE) > 0; 2169 } 2170 } else { 2171 /* traditional code */ 2172ask_again2: 2173 menu_on_request = 0; 2174 add_valid_menu_class(0); /* reset */ 2175 Strcpy(pbuf, ":ynq"); 2176 if (cnt) Strcat(pbuf, "m"); 2177 switch (yn_function(qbuf, pbuf, 'n')) { 2178 case ':': 2179 container_contents(current_container, FALSE, FALSE); 2180 goto ask_again2; 2181 case 'y': 2182 if (query_classes(select, &one_by_one, &allflag, 2183 "take out", current_container->cobj, 2184 FALSE, 2185#ifndef GOLDOBJ 2186 FALSE, 2187#endif 2188 &menu_on_request)) { 2189 if (askchain((struct obj **)¤t_container->cobj, 2190 (one_by_one ? (char *)0 : select), 2191 allflag, out_container, 2192 (int FDECL((*),(OBJ_P)))0, 2193 0, "nodot")) 2194 used = 1; 2195 } else if (menu_on_request < 0) { 2196 used |= menu_loot(menu_on_request, 2197 current_container, FALSE) > 0; 2198 } 2199 /*FALLTHRU*/ 2200 case 'n': 2201 break; 2202 case 'm': 2203 menu_on_request = -2; /* triggers ALL_CLASSES */ 2204 used |= menu_loot(menu_on_request, current_container, FALSE) > 0; 2205 break; 2206 case 'q': 2207 default: 2208 return used; 2209 } 2210 } 2211 } else { 2212 pline("%s", emptymsg); /* <whatever> is empty. */ 2213 } 2214 2215#ifndef GOLDOBJ 2216 if (!invent && u.ugold == 0) { 2217#else 2218 if (!invent) { 2219#endif 2220 /* nothing to put in, but some feedback is necessary */ 2221 You("don't have anything to put in."); 2222 return used; 2223 } 2224 if (flags.menu_style != MENU_FULL) { 2225 Sprintf(qbuf, "Do you wish to put %s in?", something); 2226 Strcpy(pbuf, ynqchars); 2227 if (flags.menu_style == MENU_TRADITIONAL && invent && inv_cnt() > 0) 2228 Strcat(pbuf, "m"); 2229 switch (yn_function(qbuf, pbuf, 'n')) { 2230 case 'y': 2231 loot_in = TRUE; 2232 break; 2233 case 'n': 2234 break; 2235 case 'm': 2236 add_valid_menu_class(0); /* reset */ 2237 menu_on_request = -2; /* triggers ALL_CLASSES */ 2238 used |= menu_loot(menu_on_request, current_container, TRUE) > 0; 2239 break; 2240 case 'q': 2241 default: 2242 return used; 2243 } 2244 } 2245 /* 2246 * Gone: being nice about only selecting food if we know we are 2247 * putting things in an ice chest. 2248 */ 2249 if (loot_in) { 2250#ifndef GOLDOBJ 2251 if (u.ugold) { 2252 /* 2253 * Hack: gold is not in the inventory, so make a gold object 2254 * and put it at the head of the inventory list. 2255 */ 2256 u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */ 2257 u_gold->in_use = TRUE; 2258 u.ugold = u_gold->quan; /* put the gold back */ 2259 assigninvlet(u_gold); /* might end up as NOINVSYM */ 2260 u_gold->nobj = invent; 2261 invent = u_gold; 2262 } 2263#endif 2264 add_valid_menu_class(0); /* reset */ 2265 if (flags.menu_style != MENU_TRADITIONAL) { 2266 used |= menu_loot(0, current_container, TRUE) > 0; 2267 } else { 2268 /* traditional code */ 2269 menu_on_request = 0; 2270 if (query_classes(select, &one_by_one, &allflag, "put in", 2271 invent, FALSE, 2272#ifndef GOLDOBJ 2273 (u.ugold != 0L), 2274#endif 2275 &menu_on_request)) { 2276 (void) askchain((struct obj **)&invent, 2277 (one_by_one ? (char *)0 : select), allflag, 2278 in_container, ck_bag, 0, "nodot"); 2279 used = 1; 2280 } else if (menu_on_request < 0) { 2281 used |= menu_loot(menu_on_request, 2282 current_container, TRUE) > 0; 2283 } 2284 } 2285 } 2286 2287#ifndef GOLDOBJ 2288 if (u_gold && invent && invent->oclass == COIN_CLASS) { 2289 /* didn't stash [all of] it */ 2290 u_gold = invent; 2291 invent = u_gold->nobj; 2292 u_gold->in_use = FALSE; 2293 dealloc_obj(u_gold); 2294 } 2295#endif 2296 return used; 2297} 2298 2299/* Loot a container (take things out, put things in), using a menu. */ 2300STATIC_OVL int 2301menu_loot(retry, container, put_in) 2302int retry; 2303struct obj *container; 2304boolean put_in; 2305{ 2306 int n, i, n_looted = 0; 2307 boolean all_categories = TRUE, loot_everything = FALSE; 2308 char buf[BUFSZ]; 2309 const char *takeout = "Take out", *putin = "Put in"; 2310 struct obj *otmp, *otmp2; 2311 menu_item *pick_list; 2312 int mflags, res; 2313 long count; 2314 2315 if (retry) { 2316 all_categories = (retry == -2); 2317 } else if (flags.menu_style == MENU_FULL) { 2318 all_categories = FALSE; 2319 Sprintf(buf,"%s what type of objects?", put_in ? putin : takeout); 2320 mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN : 2321 ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN; 2322 n = query_category(buf, put_in ? invent : container->cobj, 2323 mflags, &pick_list, PICK_ANY); 2324 if (!n) return 0; 2325 for (i = 0; i < n; i++) { 2326 if (pick_list[i].item.a_int == 'A') 2327 loot_everything = TRUE; 2328 else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) 2329 all_categories = TRUE; 2330 else 2331 add_valid_menu_class(pick_list[i].item.a_int); 2332 } 2333 free((genericptr_t) pick_list); 2334 } 2335 2336 if (loot_everything) { 2337 for (otmp = container->cobj; otmp; otmp = otmp2) { 2338 otmp2 = otmp->nobj; 2339 res = out_container(otmp); 2340 if (res < 0) break; 2341 } 2342 } else { 2343 mflags = INVORDER_SORT; 2344 if (put_in && flags.invlet_constant) mflags |= USE_INVLET; 2345 Sprintf(buf,"%s what?", put_in ? putin : takeout); 2346 n = query_objlist(buf, put_in ? invent : container->cobj, 2347 mflags, &pick_list, PICK_ANY, 2348 all_categories ? allow_all : allow_category); 2349 if (n) { 2350 n_looted = n; 2351 for (i = 0; i < n; i++) { 2352 otmp = pick_list[i].item.a_obj; 2353 count = pick_list[i].count; 2354 if (count > 0 && count < otmp->quan) { 2355 otmp = splitobj(otmp, count); 2356 /* special split case also handled by askchain() */ 2357 } 2358 res = put_in ? in_container(otmp) : out_container(otmp); 2359 if (res < 0) { 2360 if (otmp != pick_list[i].item.a_obj) { 2361 /* split occurred, merge again */ 2362 (void) merged(&pick_list[i].item.a_obj, &otmp); 2363 } 2364 break; 2365 } 2366 } 2367 free((genericptr_t)pick_list); 2368 } 2369 } 2370 return n_looted; 2371} 2372 2373STATIC_OVL int 2374in_or_out_menu(prompt, obj, outokay, inokay) 2375const char *prompt; 2376struct obj *obj; 2377boolean outokay, inokay; 2378{ 2379 winid win; 2380 anything any; 2381 menu_item *pick_list; 2382 char buf[BUFSZ]; 2383 int n; 2384 const char *menuselector = iflags.lootabc ? "abc" : "oib"; 2385 2386 any.a_void = 0; 2387 win = create_nhwindow(NHW_MENU); 2388 start_menu(win); 2389 if (outokay) { 2390 any.a_int = 1; 2391 Sprintf(buf,"Take %s out of %s", something, the(xname(obj))); 2392 add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, 2393 buf, MENU_UNSELECTED); 2394 } 2395 menuselector++; 2396 if (inokay) { 2397 any.a_int = 2; 2398 Sprintf(buf,"Put %s into %s", something, the(xname(obj))); 2399 add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED); 2400 } 2401 menuselector++; 2402 if (outokay && inokay) { 2403 any.a_int = 3; 2404 add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, 2405 "Both of the above", MENU_UNSELECTED); 2406 } 2407 end_menu(win, prompt); 2408 n = select_menu(win, PICK_ONE, &pick_list); 2409 destroy_nhwindow(win); 2410 if (n > 0) { 2411 n = pick_list[0].item.a_int; 2412 free((genericptr_t) pick_list); 2413 } 2414 return n; 2415} 2416 2417/*pickup.c*/ 2418