[BACK]Return to pack.c CVS log [TXT][DIR] Up to [contributed] / early-roguelike / urogue

Annotation of early-roguelike/urogue/pack.c, Revision 1.1.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