/* First, let me say this is a hack solution. It's not the way I wanted to do it, but it works. I wanted to make keyrings a type of container where you could store keys. Unfortunately every attempt to do this resulted in the MUD looping. Second, I use stc for send_to_char and ptc for printf_to_char. You can add the following into your primary header, or change the references. */ #define stc send_to_char #define ptc printf_to_char /* Keyrings will enable a character to store keys on an object which will allow the unlocking of doors without the need to carry a bunch of different keys in the inventory. New item: Keyring. New commands: Hook; Hook <key> on <keyring> <slot> Each keyring will have 5 available slots, 0 - 4. Unhook; Unhook <slot> from <keyring> Remove a key from the specific slot. Known problems: A key that has been restrung will re-appear with the key's index value instead of the re-strung value. No known work-around as of yet. I'm sure one exists, but as said previously, this is hackish. That out of the way, keyrings are pretty simple to add. 1) Add a new item type: ITEM_KEYRING. 2) Add two new commands to the interps: do_hook and do_unhook. 3) Add the following code where instructed. ----> ACT_COMM.C in do_appraise ( or do_lore, or whatever, if you have it ). <---- */ OBJ_INDEX_DATA *oID; int i = 0; case ITEM_KEYRING: stc( "This is a keyring, designed to hold room keys.\n\rHolds:\n\r", ch ); for ( i = 0; i < 5; i++ ) { if ( obj->value[i] == 0 ) { ptc( ch, "Slot [%d] None{x\n\r", i ); continue; } else if ( ( oID = get_obj_index( obj->value[i] ) ) == NULL ) { ptc( ch, "An error occured processing slot %d.{x\n\r", i ); continue; } else if ( obj->value[i] > 0 ) ptc( ch, "Slot [%d] %s{x\n\r", i, oID->short_descr ); } break; /* ----> ACT_MOVE.C change has_key to look like so: <---- */ bool has_key( CHAR_DATA *ch, int key ) { OBJ_DATA *obj; int i = 0; for ( obj = ch->carrying; obj != NULL; obj = obj->next_content ) { if ( obj->pIndexData->vnum == key ) return TRUE; if ( obj->item_type == ITEM_KEYRING ) { for ( i = 0; i < 5; i++ ) { if ( obj->value[i] == key ) { ptc( ch, "You flip through %s for the key.\n\r", obj->short_descr ); return TRUE; } } } } return FALSE; } /* ----> ACT_OBJ.C add these two new commands: <---- */ void do_unhook( CHAR_DATA *ch, char *argument ) { OBJ_DATA *key, *keyring; char arg1[MIL]; char arg2[MIL]; char arg3[MIL]; int slot = 0; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); argument = one_argument( argument, arg3 ); if ( arg1[0] == '\0' ) { stc( "Syntax: Unhook <key slot> from <keyring>.\n\r", ch ); stc( "Arg1 should be the number of the keyring slot.\n\r", ch ); return; } if ( !is_number( arg1 ) ) { stc( "Syntax: Unhook <key slot> from <keyring>.\n\r", ch ); stc( "Arg1 doesn't appear to be a valid keyring slot.\n\r", ch ); return; } slot = atoi( arg1 ); if ( slot < 0 || slot > 4 ) { stc( "The slot should be a number from 0 to 4.\n\r", ch ); stc( "Arg1 doesn't appear to be a valid slot number.\n\r", ch ); return; } if ( strcmp(arg2, "from" ) ) { stc( "Syntax: Unhook <key slot> from <keyring>.\n\r", ch ); stc( "Arg2 should be 'from'.\n\r", ch ); return; } if ( ( keyring = get_obj_carry( ch, arg3, ch ) ) == NULL ) { stc( "Syntax: Unhook <key slot> from <keyring>.\n\r", ch ); stc( "You don't appear to be carrying that keyring.\n\r", ch ); return; } if ( keyring->item_type != ITEM_KEYRING ) { stc( "That doesn't appear to be a keyring.\n\r", ch ); return; } if ( keyring->value[slot] > 0 ) { key = create_object( get_obj_index( keyring->value[slot] ), 1 ); obj_to_char( key, ch ); keyring->value[slot] = 0; ptc( ch, "You remove %s from %s.\n\r", key->short_descr, keyring->short_descr ); } return; } void do_hook( CHAR_DATA *ch, char *argument ) { OBJ_DATA *key, *keyring, *newObj; char arg1[MIL]; char arg2[MIL]; char arg3[MIL]; char arg4[MIL]; int slot; argument = one_argument( argument, arg1 ); argument = one_argument( argument, arg2 ); argument = one_argument( argument, arg3 ); argument = one_argument( argument, arg4 ); if ( arg1[0] == '\0' ) { stc( "Syntax: Hook <key> on <keyring> <slot>.\n\r", ch ); stc( "Arg1 should be the name of the key.\n\r", ch ); return; } if ( strcmp(arg2, "on" ) ) { stc( "Syntax: Hook <key> on <keyring> <slot>.\n\r", ch ); stc( "Arg2 should be 'on'.\n\r", ch ); return; } if ( arg3[0] == '\0' ) { stc( "Syntax: Hook <key> on <keyring> <slot>.\n\r", ch ); stc( "Arg3 should be the name of the keyring.\n\r", ch ); return; } if ( arg4[0] == '\0' ) { stc( "Syntax: Hook <key> on <keyring> <slot>.\n\r", ch ); stc( "Arg4 should be the number of the keyring slot.\n\r", ch ); return; } if ( ( key = get_obj_carry( ch, arg1, ch ) ) == NULL ) { stc( "Syntax: Hook <key> on <keyring> <slot>.\n\r", ch ); stc( "You don't appear to be carrying that key.\n\r", ch ); return; } if ( key->item_type != ITEM_KEY ) { if ( key->item_type != ITEM_ROOM_KEY ) { stc( "That doesn't appear to be a key.\n\r", ch ); return; } } if ( ( keyring = get_obj_carry( ch, arg3, ch ) ) == NULL ) { stc( "Syntax: Hook <key> on <keyring> <slot>.\n\r", ch ); stc( "You don't appear to be carrying that keyring.\n\r", ch ); return; } if ( keyring->item_type != ITEM_KEYRING ) { stc( "That doesn't appear to be a keyring.\n\r", ch ); return; } if ( !is_number( arg4 ) ) { stc( "Syntax: Hook <key> on <keyring> <slot>.\n\r", ch ); stc( "Arg4 doesn't appear to be a valid number.\n\r", ch ); return; } slot = atoi( arg4 ); if ( slot < 0 || slot > 4 ) { stc( "The slot should be a number from 0 to 4.\n\r", ch ); stc( "Arg4 doesn't appear to be a valid slot number.\n\r", ch ); return; } if ( keyring->value[slot] == 0 ) { keyring->value[slot] = key->pIndexData->vnum; ptc( ch, "You hook %s onto %s.\n\r", key->short_descr, keyring->short_descr ); obj_from_char( key ); } else if ( keyring->value[slot] > 0 ) { newObj = create_object( get_obj_index( keyring->value[slot] ), 1 ); obj_to_char( newObj, ch ); keyring->value[slot] = key->pIndexData->vnum; ptc( ch, "You remove %s from %s and replace it with %s.\n\r", newObj->short_descr, keyring->short_descr, key->short_descr ); obj_from_char( key ); } return; } /* If you use OLC, add in something to set the initial values of the keyring to zero. If you don't init the values to 0, you'll likely run into problems. If you don't use OLC, make sure DB knows to set the index data to 0, but not the obj data itself. In my OLC, I use a method to set values when the level is set. This comes from my oedit_level. Ignore the material crap. It's included so you get an idea how the case statements look. */ switch ( pObj->item_type ) { default: pObj->weight = material_table[mat].density; pObj->cost = material_table[mat].value * material_table[mat].density; if (pObj->weight <= 0) { pObj->weight = 1; } break; case ITEM_KEYRING: pObj->value[0] = 0; pObj->value[1] = 0; pObj->value[2] = 0; pObj->value[3] = 0; pObj->value[4] = 0; break;