/* ************************************************************************ * file: item.c , Some utilities for messing Part of CopperDIKUMUD * * with items, especially for counting them in lists * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * ************************************************************************* */ #include CONFIG #if HAVE_STRINGS_H #include <strings.h> #endif #if HAVE_STRING_H #include <string.h> #endif #include "structs.h" #include "utils.h" #include "db.h" #include "error.h" #include "comm.h" #include "proto.h" /* put this in a .h file sometime */ #define LOOK_OBJS 32768 /* extern variables */ extern struct str_app_type str_app[]; extern struct room_data *world; extern struct zone_data *zone_table; extern struct room_data *world; /* lib protos */ int strcasecmp(char *s1,char *s2); /* for modes */ #define SINGLE 1 #define ALL 2 #define ALL_OF_TYPE 3 /********** How to use... ************ struct obj_data *marker,*this_item; marker=first_in_some_list; this_item=NULL; *** For a get everything type command *** while(count=count_next(&this_item,&marker)) { sprintf(buf,"There are %d %s here.\n\r",count,this_item->short_desc); send_to_char(buf,ch); } clear_item_list(first_in_some_list); *** For a get all.blue type command *** marker=get_next_blank_of_type(.....); if(marker) { while(marker) { count=count_next(&this_item,&marker); sprintf(buf,"You munge %d %s(s)\n\r",count,this_item->short_desc); send_to_char(buf,ch); marker=get_next_blank_of_type(.....); } } */ void clear_item_list(struct obj_data *obj) { struct obj_data *k; for(k=obj;k;k=k->next_content) REMOVE_BIT(k->obj_flags.extra_flags,ITEM_ARCHIVE); } int count_next(struct char_data *ch,struct obj_data **out_item, struct obj_data **marker) { struct obj_data *k; int count=0; bool blanks_yet=FALSE; *out_item=*marker; for(k=*marker;k;k=k->next_content) if(!CAN_SEE_OBJ(ch,k)) { SET_BIT(k->obj_flags.extra_flags,ITEM_ARCHIVE); } else if(isname((*marker)->name,k->name)) { SET_BIT(k->obj_flags.extra_flags,ITEM_ARCHIVE); count++; } else if(!blanks_yet) { blanks_yet=TRUE; *marker=k; } return(count); } struct obj_data *fetch_next_item(struct char_data *ch,struct obj_data *start, struct obj_data *match) { struct obj_data *k; for(k=start;k;k=k->next_content) { if(!CAN_SEE_OBJ(ch,k)) SET_BIT(k->obj_flags.extra_flags,ITEM_ARCHIVE); else if(k->item_number==match->item_number && !IS_SET(k->obj_flags.extra_flags,ITEM_ARCHIVE)) { SET_BIT(k->obj_flags.extra_flags,ITEM_ARCHIVE); return(k); } } return(NULL); } struct obj_data *fetch_next_text(struct char_data *ch,struct obj_data *start, char *text) { struct obj_data *k; for(k=start;k;k=k->next_content) { if(!CAN_SEE_OBJ(ch,k)) SET_BIT(k->obj_flags.extra_flags,ITEM_ARCHIVE); else if(isname(text,k->name) && !IS_SET(k->obj_flags.extra_flags,ITEM_ARCHIVE)) { SET_BIT(k->obj_flags.extra_flags,ITEM_ARCHIVE); return(k); } } return(NULL); } struct obj_data *find_unarchived(struct char_data *ch,struct obj_data *start) { struct obj_data *k; for(k=start;k;k=k->next_content) if(!IS_SET(k->obj_flags.extra_flags,ITEM_ARCHIVE) && CAN_SEE_OBJ(ch,k)) return(k); return(NULL); } /* Macros for different types of the following */ #define SINGLE_ITEM 1 #define ALL_ITEMS 2 #define ALL_TYPE 3 /* This is a generic way of handling items for commands which require just one "object" -> things like get, drop, wear, etc. ("put" on the other hand would not work). "flags" corresponds to a bitvector identical to that of generic_find (the CHAR bits are ignored), which correspond to what "places" items can be at for the command (foolish to "get" something already carried). The function is passed a pointer to another function to call when it has an item which satisfies the argument and parameters of the call. */ void single_item_processor(struct char_data *ch, char *argument, int cmd, int flags, bool func(struct char_data *ch, struct obj_data *obj)) { char arg1[MAX_STRING_LENGTH]; char arg2[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; struct obj_data *sub_object; struct obj_data *j,*k; struct obj_data *start_at,*this_item; int mode,bits; bool alldot = FALSE; char allbuf[MAX_STRING_LENGTH]; argument_interpreter(argument, arg1, arg2); /* get type */ if (!*arg1) { send_to_char("This interpreter is not a mind reader.\n\r\n\r",ch); return; } alldot = FALSE; allbuf[0] = '\0'; if (sscanf(arg1, "all.%s", allbuf) != 0) { mode=ALL_OF_TYPE; } else if (!str_cmp(arg1,"all")) { mode=ALL; } else { mode=SINGLE; } /* get the "first" item here */ if(!*arg2) { bits=generic_find(arg1,flags,ch,(void **)&start_at); if(!start_at) { send_to_char("There's nothing appropriate available.\n\r",ch); return; } } else if(!strcasecmp(arg2,"room")) { if(!(flags & FIND_OBJ_ROOM)) { send_to_char("You can't do that to items in the room.\n\r",ch); return; } start_at=world[ch->in_room].contents; } else if(!strcasecmp(arg2,"inventory")) { if(!(flags & FIND_OBJ_INV)) { send_to_char("You can't do that to items in your inventory.\n\r",ch); return; } start_at=ch->carrying; } else if((sub_object=get_obj_in_list_vis(ch,arg2, world[ch->in_room].contents))) { /*add "from" option? */ if(!(flags & LOOK_OBJS)) { send_to_char("You can't do that with items in containers.\n\r",ch); return; } start_at=sub_object->contains; } else { sprintf(buf,"What is %s?",arg2); send_to_char(buf,ch); return; } switch(mode) { case ALL: this_item=start_at; do { k=this_item; do { func(ch,k); } while((k=fetch_next_item(ch,k,this_item))); } while((j=find_unarchived(ch,j))); clear_item_list(start_at); break; case ALL_OF_TYPE: k=this_item; do { func(ch,k); } while((k=fetch_next_text(ch,this_item,allbuf))); clear_item_list(start_at); break; case SINGLE: func(ch,start_at); break; default: log("BUG: Bad mode in single_item_processor!"); send_to_char("Bug! Please report\n\r",ch); break; } }