Annotation of early-roguelike/urogue/pack.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: pack.c - Routines to deal with the pack.
! 3:
! 4: UltraRogue: The Ultimate Adventure in the Dungeons of Doom
! 5: Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
! 6: All rights reserved.
! 7:
! 8: Based on "Advanced Rogue"
! 9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
! 10: All rights reserved.
! 11:
! 12: Based on "Rogue: Exploring the Dungeons of Doom"
! 13: Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
! 14: All rights reserved.
! 15:
! 16: See the file LICENSE.TXT for full copyright and licensing information.
! 17: */
! 18:
! 19: /*
! 20: Notes
! 21:
! 22: The new pack is implemented through the use of bags,
! 23: and items are classed by their types (see rogue.h) which also
! 24: happen to be their display character.
! 25: */
! 26:
! 27: #include <stdlib.h>
! 28: #include <ctype.h>
! 29: #include "rogue.h"
! 30:
! 31: #define ESCAPE_EXIT(x) if (x == ESCAPE) {after = FALSE; msg(""); return(NULL);}
! 32: #define BAD_NEWS -1
! 33: #define BAD_LIST ((struct linked_list *) BAD_NEWS)
! 34: #define GOOD_NEWS 0
! 35:
! 36: static char type_list[] = "!?])/=:,"; /* things to inventory */
! 37:
! 38: /*
! 39: swap_top()
! 40: Takes an stacked object and exchanges places with the top
! 41: object. <node> must belong to the <top>'s stacked object list.
! 42: */
! 43:
! 44: void
! 45: swap_top(struct linked_list *top, struct linked_list *node)
! 46: {
! 47: struct object *obt, *obn;
! 48:
! 49: obt = OBJPTR(top);
! 50: obn = OBJPTR(node);
! 51:
! 52: detach((obt->next_obj), node); /* Take it out of the stack */
! 53: attach(lvl_obj, node); /* and put it into the level */
! 54: detach(lvl_obj, top); /* Remove item from level */
! 55:
! 56: obn->next_obj = obt->next_obj;
! 57: obt->next_obj = NULL;
! 58:
! 59: if (obn->next_obj)
! 60: obn->next_obj->l_prev = NULL;
! 61:
! 62: attach((obn->next_obj), top);
! 63: }
! 64:
! 65:
! 66: /*
! 67: get_all()
! 68: Get as many stacked items as possible.
! 69: */
! 70:
! 71: void
! 72: get_all(struct linked_list *top)
! 73: {
! 74: struct linked_list *node;
! 75: struct object *obt;
! 76:
! 77: while (top)
! 78: {
! 79: obt = OBJPTR(top);
! 80: node = obt->next_obj;
! 81:
! 82: rem_obj(top, FALSE);
! 83:
! 84: if (!add_pack(top, FALSE))
! 85: return;
! 86:
! 87: top = node;
! 88: }
! 89: }
! 90:
! 91:
! 92: /*
! 93: get_stack()
! 94: Allows the user to chose from a stack of items.
! 95: */
! 96:
! 97: struct linked_list *
! 98: get_stack(struct linked_list *item)
! 99: {
! 100: struct object *obj;
! 101: char buf[2 * LINELEN];
! 102: int i = 0, j;
! 103: struct linked_list *ll;
! 104: mpos = 0;
! 105: obj = OBJPTR(item);
! 106:
! 107: ll = obj->next_obj;
! 108:
! 109: sprintf(buf, "You are standing on top of the following items: ");
! 110: add_line(buf);
! 111: sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
! 112: add_line(buf);
! 113:
! 114: while (ll)
! 115: {
! 116: i++;
! 117: obj = OBJPTR(ll);
! 118: sprintf(buf, "%d) -- %s", i, inv_name(obj, TRUE));
! 119: add_line(buf);
! 120: ll = next(ll);
! 121: }
! 122:
! 123: end_line();
! 124:
! 125: msg("Which one do you want to pick up? [* for all] ");
! 126:
! 127: switch(get_string(buf, cw))
! 128: {
! 129: case NORM:
! 130: break;
! 131: case QUIT: /* pick up nothing */
! 132: msg("");
! 133: return (NULL);
! 134: }
! 135:
! 136: if (buf[0] == '*')
! 137: {
! 138: get_all(item);
! 139: msg("");
! 140: return(NULL);
! 141: }
! 142: else
! 143: {
! 144: i = atoi(buf);
! 145:
! 146: if (i)
! 147: {
! 148: obj = OBJPTR(item);
! 149: ll = obj->next_obj;
! 150: j = 1;
! 151:
! 152: while (ll && (j != i))
! 153: {
! 154: ll = next(ll);
! 155: j++;
! 156: }
! 157:
! 158: if (ll)
! 159: {
! 160: swap_top(item, ll);
! 161: return(ll);
! 162: }
! 163: else
! 164: {
! 165: debug("Got past last item while picking up.");
! 166: return(item);
! 167: }
! 168: }
! 169: else
! 170: return (item);
! 171: }
! 172: }
! 173:
! 174: /*
! 175: add_pack()
! 176: Pick up an object and add it to the pack. If the argument is
! 177: non-null use it as the linked_list pointer instead of getting it off the
! 178: ground.
! 179: */
! 180:
! 181: int
! 182: add_pack(struct linked_list *item, int print_message)
! 183: {
! 184: struct object *obj, *op;
! 185: int from_floor;
! 186:
! 187: if (item == NULL)
! 188: {
! 189: from_floor = TRUE;
! 190:
! 191: if ((item = find_obj(hero.y, hero.x)) == NULL)
! 192: {
! 193: msg("Nothing to pick up.");
! 194: return(FALSE);
! 195: }
! 196: }
! 197: else
! 198: from_floor = FALSE;
! 199:
! 200: if (from_floor)
! 201: {
! 202: item = get_stack(item);
! 203:
! 204: if (!item)
! 205: return(FALSE);
! 206: }
! 207:
! 208: obj = OBJPTR(item);
! 209:
! 210: /* If it is gold, just add its value to rogue's purse and get rid of */
! 211:
! 212: if (obj->o_type == GOLD)
! 213: {
! 214: struct linked_list *mitem;
! 215: struct thing *tp;
! 216:
! 217: if (print_message)
! 218: {
! 219: if (!terse)
! 220: addmsg("You found ");
! 221:
! 222: msg("%d gold pieces.", obj->o_count);
! 223: }
! 224:
! 225: /*
! 226: * First make sure no greedy monster is after this gold. If
! 227: * so, make the monster run after the rogue instead.
! 228: */
! 229:
! 230: for (mitem = mlist; mitem != NULL; mitem = next(mitem))
! 231: {
! 232: tp = THINGPTR(mitem);
! 233:
! 234: if (tp->t_horde==obj)
! 235: {
! 236: tp->t_ischasing = TRUE;
! 237: tp->t_chasee = &player;
! 238: tp->t_horde = NULL;
! 239: }
! 240: }
! 241:
! 242: /*
! 243: * This will cause problems if people are able to drop and
! 244: * pick up gold, or when GOLDSTEAL monsters are killed.
! 245: */
! 246:
! 247: /* Thieves get EXP for gold they pick up */
! 248:
! 249: if (player.t_ctype == C_THIEF)
! 250: {
! 251: pstats.s_exp += obj->o_count / 4;
! 252: check_level();
! 253: }
! 254:
! 255: purse += obj->o_count;
! 256:
! 257: if (from_floor)
! 258: rem_obj(item, TRUE); /* Remove object from the level */
! 259:
! 260: return (TRUE);
! 261: }
! 262:
! 263: /* see if he can carry any more weight */
! 264:
! 265: if (itemweight(obj) + pstats.s_pack > pstats.s_carry)
! 266: {
! 267: msg("Too much for you to carry.");
! 268:
! 269: if (print_message)
! 270: {
! 271: msg("%s onto %s", terse ? "Moved" : "You moved",
! 272: inv_name(obj, LOWERCASE));
! 273: }
! 274:
! 275: return(FALSE);
! 276: }
! 277:
! 278: /*
! 279: * Link it into the pack. If the item can be grouped, try to find its
! 280: * neighbors and bump the count. A special case is food, which can't
! 281: * be grouped, but an exact match allows the count to get
! 282: * incremented.
! 283: */
! 284:
! 285: if ((op = apply_to_bag(pack, obj->o_type, bff_group, NULL, obj)) != NULL)
! 286: {
! 287: op->o_count += obj->o_count; /* add it to the rest */
! 288:
! 289: if (from_floor)
! 290: rem_obj(item, FALSE);
! 291:
! 292: pack_report(op, print_message, "You now have ");
! 293:
! 294: return(TRUE);
! 295: }
! 296:
! 297: /* Check for and deal with scare monster scrolls */
! 298:
! 299: if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
! 300: if (obj->o_flags & ISCURSED)
! 301: {
! 302: msg("The scroll turns to dust as you pick it up.");
! 303: rem_obj(item, TRUE);
! 304: return(TRUE);
! 305: }
! 306:
! 307: /* Check if there is room */
! 308:
! 309: if (count_bag(pack, obj->o_type, NULL) == max_print())
! 310: {
! 311: msg("You have no room for more %s.", name_type(obj->o_type));
! 312:
! 313: if (print_message)
! 314: {
! 315: obj = OBJPTR(item);
! 316: msg("%s onto %s.", terse ? "Moved" : "You moved",
! 317: inv_name(obj, LOWERCASE));
! 318: }
! 319:
! 320: return(FALSE);
! 321: }
! 322:
! 323: /*
! 324: * finally, add the new item to the bag, and free up the linked list
! 325: * on top of it.
! 326: */
! 327:
! 328: if (from_floor)
! 329: rem_obj(item, FALSE);
! 330:
! 331: push_bag(&pack, obj);
! 332: pack_report(obj, print_message, "You now have ");
! 333: ur_free(item);
! 334:
! 335: return(TRUE); /* signal success */
! 336: }
! 337:
! 338: /*
! 339: pack_report()
! 340: Notify the user about the results of the pack operation and do some
! 341: post processing.
! 342: */
! 343:
! 344: void
! 345: pack_report(object *obj, int print_message, char *message)
! 346: {
! 347: /* Notify the user */
! 348:
! 349: if (print_message)
! 350: {
! 351: if (!terse)
! 352: addmsg(message);
! 353:
! 354: msg("(%c%c) %s.", obj->o_type, print_letters[get_ident(obj)],
! 355: inv_name(obj, !terse));
! 356: }
! 357:
! 358: if (obj->o_type == ARTIFACT)
! 359: {
! 360: has_artifact |= (1 << obj->o_which);
! 361: picked_artifact |= (1 << obj->o_which);
! 362:
! 363: if (!(obj->ar_flags & ISUSED))
! 364: {
! 365: obj->ar_flags |= ISUSED;
! 366: pstats.s_exp += arts[obj->o_which].ar_worth / 10;
! 367: check_level();
! 368: }
! 369: }
! 370:
! 371: updpack();
! 372:
! 373: return;
! 374: }
! 375:
! 376: /*
! 377: inventory()
! 378: list what is in the pack
! 379: */
! 380:
! 381: void
! 382: inventory(struct linked_list *container, int type)
! 383: {
! 384: int cnt;
! 385:
! 386: if (type == 0)
! 387: {
! 388: msg("What kind of item <%s> to inventory (* for all)?", type_list);
! 389:
! 390: type = readchar();
! 391:
! 392: if (type == ESCAPE)
! 393: {
! 394: after = FALSE;
! 395: msg("");
! 396: return;
! 397: }
! 398: }
! 399:
! 400: /*
! 401: * Get a list of items to print out. If the user selects '*', list
! 402: * them all.
! 403: */
! 404:
! 405: if (type == '*')
! 406: type = 0; /* no type passed ->use them all */
! 407:
! 408: mpos = 0;
! 409:
! 410: if ((cnt = count_bag(container, type, NULL)) == 0)
! 411: msg("You don't have any %s.", name_type(type));
! 412: else
! 413: {
! 414: apply_to_bag(container, type, NULL, baf_print_item, &type);
! 415: end_line();
! 416: msg("");
! 417: }
! 418:
! 419: return;
! 420: }
! 421:
! 422: /*
! 423: pick_up()
! 424: Add something to characters pack.
! 425: */
! 426:
! 427: void
! 428: pick_up(char ch)
! 429: {
! 430: switch(ch)
! 431: {
! 432: default:
! 433: debug("Where did you pick that up???");
! 434: break;
! 435:
! 436: case GOLD:
! 437: case ARMOR:
! 438: case POTION:
! 439: case FOOD:
! 440: case WEAPON:
! 441: case SCROLL:
! 442: case ARTIFACT:
! 443: case RING:
! 444: case STICK:
! 445: add_pack(NULL, MESSAGE);
! 446: break;
! 447: }
! 448: }
! 449:
! 450: /*
! 451: get_object()
! 452:
! 453: Pick something out of a pack for a purpose. The basic idea is to
! 454: list all the possibilities, let the user select one, get that item
! 455: from the container, and pass it back to the calling routine.
! 456: */
! 457:
! 458: struct object *
! 459: get_object(struct linked_list *container, char *purpose, int type, int (*bff_p)(struct object *obj, bag_arg *junk))
! 460: /* char *container; what container has what we want */
! 461: /* char *purpose; a message (verb) to print if we cant find any */
! 462: /* char type; type (o_type) to pick out (NULL = any) */
! 463: /* int (*bff_p) (); bag filter function to test item */
! 464: {
! 465: struct object *obj_p = NULL;
! 466: char sel_id; /* selected type and id */
! 467: int sel_type;
! 468: char response;
! 469:
! 470: if (container == NULL)
! 471: {
! 472: msg("There isn't anything in there.");
! 473: after = FALSE;
! 474: return(NULL);
! 475: }
! 476:
! 477: /* Make sure we have at least one item that qualifies! */
! 478:
! 479: if (apply_to_bag(container, type, bff_p, NULL, NULL) == NULL)
! 480: {
! 481: msg("You seem to have nothing to %s.", purpose);
! 482: after = FALSE;
! 483: return(NULL);
! 484: }
! 485:
! 486: while (obj_p == NULL)
! 487: {
! 488: if (type == 0)
! 489: {
! 490: msg("What kind of item <%s> do you want to %s (* for list)?", type_list, purpose);
! 491:
! 492: response = readchar();
! 493: ESCAPE_EXIT(response);
! 494: msg("");
! 495:
! 496: if (response == '*')
! 497: {
! 498: add_line("! Potion");
! 499: add_line("? Scroll");
! 500: add_line("= Ring");
! 501: add_line("/ Stick");
! 502: add_line("] Armor");
! 503: add_line(") Weapon");
! 504: add_line(": Food");
! 505: end_line();
! 506: continue;
! 507: }
! 508:
! 509:
! 510: if (!is_member(type_list, response)) { beep();
! 511: continue; }
! 512:
! 513:
! 514: if (count_bag(container, response, NULL) == 0)
! 515: {
! 516: msg("You don't have any %s.", name_type(response));
! 517: continue;
! 518: }
! 519:
! 520: type = response;
! 521: }
! 522:
! 523: while(obj_p == NULL)
! 524: {
! 525: msg("What item do you want to %s (* for list)?", purpose);
! 526: response = readchar();
! 527: msg("");
! 528: ESCAPE_EXIT(response);
! 529:
! 530: if (response == '*')
! 531: {
! 532: mpos = 0;
! 533: apply_to_bag(container, type, bff_p, baf_print_item, &type);
! 534: end_line();
! 535: continue;
! 536: }
! 537:
! 538: sel_type = type;
! 539: sel_id = response;
! 540:
! 541: obj_p = scan_bag(container, sel_type,unprint_id(&sel_id));
! 542: }
! 543: }
! 544:
! 545: mpos = 0;
! 546: msg("");
! 547: return(obj_p);
! 548: }
! 549:
! 550: /*
! 551: get_item()
! 552:
! 553: This is only an interim function that serves as an interface to
! 554: the old function get_item and its replacement get_object. It
! 555: assumes a NULL action routine and allocates a linked_list
! 556: structure on top of the object pointer.
! 557: */
! 558:
! 559: struct linked_list *
! 560: get_item(char *purpose, int type)
! 561: {
! 562: struct object *obj_p;
! 563:
! 564: if ((obj_p = get_object(pack, purpose, type, NULL)) == NULL)
! 565: return(NULL);
! 566:
! 567: return(make_item(obj_p));
! 568: }
! 569:
! 570: /*
! 571: del_pack()
! 572: Take something out of the hero's pack and throw it away.
! 573: */
! 574:
! 575: void
! 576: del_pack(struct linked_list *what)
! 577: {
! 578: rem_pack(OBJPTR(what));
! 579: discard(what);
! 580: }
! 581:
! 582: /*
! 583: discard_pack
! 584: take an object from the pack and throw it away (like del_pack,
! 585: but without the linked_list structure)
! 586: */
! 587:
! 588: void
! 589: discard_pack(struct object *obj_p)
! 590: {
! 591: rem_pack(obj_p);
! 592: throw_away(obj_p);
! 593: }
! 594:
! 595: /*
! 596: rem_pack()
! 597: Removes an item from the pack.
! 598: */
! 599:
! 600: void
! 601: rem_pack(struct object *obj_p)
! 602: {
! 603: cur_null(obj_p); /* check for current stuff */
! 604: pop_bag(&pack, obj_p);
! 605: updpack();
! 606: return; /* tell caller an item has been removed */
! 607: }
! 608:
! 609: /*
! 610: cur_null()
! 611: This updates cur_weapon etc for dropping things
! 612: */
! 613:
! 614: void
! 615: cur_null(struct object *op)
! 616: {
! 617: if (op == cur_weapon)
! 618: cur_weapon = NULL;
! 619: else if (op == cur_armor)
! 620: cur_armor = NULL;
! 621: else if (op == cur_ring[LEFT_1])
! 622: cur_ring[LEFT_1] = NULL;
! 623: else if (op == cur_ring[LEFT_2])
! 624: cur_ring[LEFT_2] = NULL;
! 625: else if (op == cur_ring[LEFT_3])
! 626: cur_ring[LEFT_3] = NULL;
! 627: else if (op == cur_ring[LEFT_4])
! 628: cur_ring[LEFT_4] = NULL;
! 629: else if (op == cur_ring[LEFT_5])
! 630: cur_ring[LEFT_5] = NULL;
! 631: else if (op == cur_ring[RIGHT_1])
! 632: cur_ring[RIGHT_1] = NULL;
! 633: else if (op == cur_ring[RIGHT_2])
! 634: cur_ring[RIGHT_2] = NULL;
! 635: else if (op == cur_ring[RIGHT_3])
! 636: cur_ring[RIGHT_3] = NULL;
! 637: else if (op == cur_ring[RIGHT_4])
! 638: cur_ring[RIGHT_4] = NULL;
! 639: else if (op == cur_ring[RIGHT_5])
! 640: cur_ring[RIGHT_5] = NULL;
! 641: }
! 642:
! 643: /*
! 644: idenpack()
! 645: Identify all the items in the pack
! 646: */
! 647:
! 648: void
! 649: idenpack(void)
! 650: {
! 651: apply_to_bag(pack, 0, NULL, baf_identify, NULL);
! 652: }
! 653:
! 654: /*
! 655: show_floor()
! 656: Print out the item on the floor. Used by the move command.
! 657: */
! 658:
! 659: void
! 660: show_floor(void)
! 661: {
! 662: struct linked_list *item;
! 663: struct object *obj;
! 664:
! 665: item = find_obj(hero.y, hero.x);
! 666:
! 667: if (item != NULL)
! 668: {
! 669: addmsg("%s onto ", terse ? "Moved" : "You moved");
! 670:
! 671: obj = OBJPTR(item);
! 672:
! 673: if (obj->next_obj != NULL)
! 674: msg("a stack of things.");
! 675: else if (obj->o_type == GOLD)
! 676: msg("%d gold pieces.", obj->o_count);
! 677: else
! 678: {
! 679: addmsg(inv_name(obj, TRUE));
! 680: addmsg(".");
! 681: endmsg();
! 682: }
! 683: }
! 684: }
CVSweb