/*************************************************************************** * Keyring [C] 2002 Petr [Dingo] Dvorak <dingo@texoma.net> * * * * Written for Anime Planet MUD [animeplanet.genesismuds.com:3333] * ***************************************************************************/ #include <stdio.h> #include <string.h> #include "merc.h" // some state definitions so we can handle all the states with one function // instead repeating the same stuff over and over. #define KR_OK 0 #define KR_NO_KEYRING 1 #define KR_NO_KEY 2 #define KR_NO_REMKEY 3 #define KR_INVALID_KEYRING 4 #define KR_INVALID_KEY 5 #define KR_INVALID_NAME 6 #define KR_KEY_DUP 7 DECLARE_DO_FUN( do_examine ); /* This snippet adds keyring command and ability into the mud, the syntax is simple: keyring - examine the keyring and lists all keys. keyring add <key> - add key to the keyring. keyring remove <key> - remove key from keyring. when player adds a key on keyring, the physical key is extracted, when player removes key from keyring, the physical key is created and inserted in their inventory. There is not that much to this snippet so write your own help for it. I didn't want to add another object type just for something simple like this, so the code looks for name prefix 'keyring' in the pObjIndex->name, this way the keyrings can still have restring name and work like keyrings. You need to make sure that there is no objects with 'keyring' in name that you don't want the players to use as keyrings. simple 'vnum keyring' on the mud should suffice. just drop the stuff below into the proper files, places and add keyring.o to O_FILES in Makefile. If you look over the code (like you should of course), you will see i like structured calls alot, it keeps the main functions at manageable size and somewhat better readable. there is no warranty of any kind, not even that this will work of course. if something breaks, you get to keep both pieces :) I'm not very big on comments in the code, so this is about as good as it gets, if you need more info on what does what just email me. --[ merc.h ]-------------------------------------------------------------------- typedef struct key_data KEY_DATA; // keyring struct key_data { KEY_DATA * next; bool valid; OBJ_INDEX_DATA * index; }; // keyring.c KEY_DATA * new_key args( (void ) ); OBJ_DATA * find_keyring args( (CHAR_DATA * ch ) ); int remove_key args( (CHAR_DATA * ch, OBJ_DATA * keyring, char * name ) ); int add_key args( (OBJ_DATA * keyring, OBJ_DATA * key ) ); void free_key args( (KEY_DATA * key ) ); void list_keys args( (CHAR_DATA * ch, OBJ_DATA * keyring ) ); void load_keyring args( (FILE * fp, OBJ_DATA * obj ) ); void save_keyring args( (FILE * fp, OBJ_DATA * obj ) ); add in obj_data structure: KEY_DATA * keys; // keyring --[ interp.h ]------------------------------------------------------------------ DECLARE_DO_FUN( do_keyring ); --[ interp.c ]------------------------------------------------------------------ add the hook in command table .. just below "kill" { "keyring", do_keyring, POS_FIGHTING, 1, LOG_NORMAL }, --[ act_move.c ]---------------------------------------------------------------- replace the has_key in act_move.c with this one: bool has_key( CHAR_DATA *ch, int key ) { OBJ_DATA *obj; KEY_DATA *keys; for ( obj = ch->carrying; obj != NULL; obj = obj->next_content ) { if ( obj->pIndexData->vnum == key ) return TRUE; } // look for the keyring in players inventory obj = find_keyring(ch); // no keyring found ? if (!obj) return FALSE; // loop thru the keys on keyring and see if there is a matching key for (keys = obj->keys; keys != NULL; keys = keys->next) { if ( keys->index->vnum == key ) { send_to_char("After some searching of your keyring, you found a key that seems to fit the lock.\n\r", ch); return TRUE; } } // no keys found return FALSE; } --[ save.c ]-------------------------------------------------------------------- add this in fwrite_obj: if ( obj->keys ) save_keyring( fp, obj); and this in fread_obj in the switch loop: case 'K': if ( !str_cmp( word, "Keyring" ) ) { // load list of key vnums from pfile load_keyring(fp, obj) fMatch = TRUE; } break; --[ recycle.c ]----------------------------------------------------------------- add the following in apropriate places in free_obj: on the begining: KEY_DATA * key, * key_next; somewhere on the end: if (obj->keys) { // loop thru the keys and free the allocated memory for ( key = obj->keys; key != NULL; key = key_next) { key_next = key->next; free_key(key); } } -------------------------------------------------------------------------------- */ // allocates memory for new key on the keyring KEY_DATA * new_key( void ) { KEY_DATA * key; // allocate memory for the key, calloc 0's the allocated memory so we don't // have to initialize the variables. key = calloc(1,sizeof(*key)); VALIDATE(key); return key; } // frees memory allocated by new_key void free_key( KEY_DATA * key ) { // usual sanity checks if (!key || !IS_VALID(key)) return; // clean up, makes debugging easier :) key->next = NULL; key->index = NULL; // this can NEVER be free'd here !!! INVALIDATE(key); // free the memory free(key); return; } // adds key to the keyring int add_key( OBJ_DATA * keyring, OBJ_DATA * key) { KEY_DATA * nkey; // the usual sanity checks if (!keyring) return KR_NO_KEYRING; if (!key) return KR_NO_KEY; if (!IS_VALID(keyring)) return KR_INVALID_KEYRING; if (!IS_VALID(key)) return KR_INVALID_KEY; // loop thru the keyring and make sure that the key is not already on it for ( nkey = keyring->keys; nkey != NULL; nkey = nkey->next ) if (nkey->index == key->pIndexData) return KR_KEY_DUP; nkey = new_key(); // fill in the data nkey->index = key->pIndexData; // add the key to the keyring nkey->next = keyring->keys; keyring->keys = nkey; // get rid of the 'real' key obj_from_char(key); extract_obj(key); return KR_OK; } // removes key from the keyring int remove_key( CHAR_DATA * ch, OBJ_DATA * keyring, char * name ) { KEY_DATA * key; KEY_DATA * key_next; // usual sanity check if (!keyring) return KR_NO_KEYRING; if (!keyring->keys) return KR_NO_KEY; if (!name) return KR_INVALID_NAME; if (name[0] == '\0') return KR_INVALID_NAME; // let's find the key for ( key = keyring->keys; key != NULL; key = key_next ) { key_next = key->next; // check the name if (key && key->index->name && !str_prefix(name, key->index->name)) { OBJ_DATA *phys_key; // create physical key and put it in players inventory phys_key = create_object(key->index,key->index->level); obj_to_char(phys_key, ch); // if the key is first on the ring, its easy to drop it if ( keyring->keys == key ) keyring->keys = key->next; else // we gotta find the previous key { KEY_DATA *prev; for ( prev = keyring->keys; prev != NULL; prev = prev->next ) { if ( prev->next == key ) { // drop the key from the ring; prev->next = key->next; break; } } } // free the key structure free_key(key); // time to bail. return KR_OK; } } // hmm, we are still around ? key was not found. return KR_NO_REMKEY; } void save_keyring( FILE * fp, OBJ_DATA * obj) { KEY_DATA * keys; // the usual sanity check if (!obj || !obj->keys) return; fprintf(fp, "Keyring "); // loop thru the keys on keyring and save the vnums for (keys = obj->keys; keys != NULL; keys = keys->next) { if ( keys->index->vnum ) fprintf(fp, "%d ", keys->index->vnum); } // save -1 on the end of the list to terminate it fprintf(fp,"-1\n\r"); return; } // load keys from the pfile void load_keyring( FILE * fp, OBJ_DATA * obj) { int vnum = 0; KEY_DATA * nkey; do { // read one vnum from the pfile vnum = FREAD_NUMBER(fp); if (vnum > 0) { // create new key nkey = new_key(); // fill in the blanks nkey->index = get_obj_index(vnum); nkey->next = obj->keys; obj->keys = nkey; } } while (vnum > 0); return; } // lists the keys on the keyring void list_keys( CHAR_DATA * ch, OBJ_DATA * keyring ) { KEY_DATA * key; char buf[MSL]; // no keys on the keyring if ( !keyring->keys ) { send_to_char("The keyring is empty.\n\r",ch); return; } // list the keys send_to_char("\n\rThe keyring contains the following keys:\n\r\n\r",ch); for ( key = keyring->keys; key != NULL; key = key->next) { buf[0] = '\0'; // imms can see vnums of the keys in the list. if (IS_IMMORTAL(ch)) sprintf(buf,"{D[{C%5.5d{D]{x",key->index->vnum); // send out the formatted line printf_to_char(ch," %s %s from %s.\n\r", buf, key->index->short_descr ? key->index->short_descr : "Unknown", key->index->area->name ? key->index->area->name : "Unknown place" ); } return; } // searches players inventory for keyring OBJ_DATA * find_keyring( CHAR_DATA * ch ) { OBJ_DATA *obj; // search players inventory for keyring object for ( obj = ch->carrying; obj != NULL; obj = obj->next_content ) { if ( (can_see_obj( ch, obj ) ) && !str_prefix( "keyring", obj->name ) ) return obj; } return NULL; } void keyring_message(int message, CHAR_DATA * ch, OBJ_DATA * key) { switch (message) { case KR_OK: // everything ok .. what are we doing here ? return; break; case KR_NO_KEYRING: // no keyring send_to_char("You don't have a keyring, go buy one.\n\r",ch); break; case KR_NO_KEY: // no key send_to_char("You don't have that key.\n\r",ch); break; case KR_NO_REMKEY: // no key on keyring send_to_char("You don't have that key on your keyring.\n\r",ch); break; case KR_KEY_DUP: printf_to_char(ch, "You already have %s on your keyring.\n\r",key->short_descr); break; case KR_INVALID_NAME: case KR_INVALID_KEYRING: case KR_INVALID_KEY: default: send_to_char("Something gone horribly wrong, please tell the nearest immortal.\n\r",ch); // add your own debugging code here break; } return; } // the command function void do_keyring( CHAR_DATA * ch, char *argument ) { OBJ_DATA * keyring = NULL; OBJ_DATA * key = NULL; char arg1[MIL]; char arg2[MIL]; int message = KR_OK; keyring = find_keyring(ch); if (!keyring) { keyring_message(KR_NO_KEYRING,ch,NULL); return; } // no arguments ? just show list of the keys on the keyring then. if (argument[0] == '\0') { // yes i know, this is really filthy way to do this, but this way it // will show the same stuff like if people examine normal object // every mud is little different :) do_examine(ch, keyring->name); return; } argument = one_argument( argument, arg1 ); // command - add | remove argument = one_argument( argument, arg2 ); // key name if (arg2[0] == '\0' ) { send_to_char("You must specify the name of the key you wish to add or remove.\n\r", ch); return; } if (is_name( arg1, "add") ) { key = get_obj_carry( ch, arg2, ch ); if (!key) { send_to_char("You don't have that key.\n\r", ch); return; } if (key->item_type != ITEM_KEY) { send_to_char("That is not a key!\n\r", ch); return; } message = add_key(keyring, key); if (!message) { act("$n adds $p on $s keyring.", ch, key, NULL, TO_ROOM, POS_RESTING); act("You added $p on your keyring.", ch, key, NULL, TO_CHAR, POS_RESTING); } else { keyring_message(message,ch,key); } } else if (is_name( arg1, "remove" ) ) { message = remove_key(ch, keyring, arg2); if (!message) { act("$n removes a key from $s keyring.", ch, NULL, NULL, TO_ROOM, POS_RESTING); act("You removed a key from your keyring.", ch, NULL, NULL, TO_CHAR, POS_RESTING); } else { keyring_message(message,ch,NULL); } } else { send_to_char("What exactly do you want to do with the keyring ?\n\r", ch); return; } return; }