To add in a new type skill you begin in mud.h with this section: typedef enum { SKILL_UNKNOWN, SKILL_SPELL, SKILL_SKILL, SKILL_WEAPON, SKILL_TONGUE, SKILL_HERB, SKILL_RACIAL, SKILL_DISEASE } skill_types; You will be creating an entirely new partition in your skill table, which is a very delicate task. In the above listing, SKILL_UNKNOWN to SKILL_TONGUE all occupy one partition of your skill_table. Those are defined just above this portion: #define TYPE_UNDEFINED -1 #define TYPE_HIT 1000 /* allows for 1000 skills/spells */ #define TYPE_HERB 2000 /* allows for 1000 attack types */ #define TYPE_PERSONAL 3000 /* allows for 1000 herb types */ #define TYPE_RACIAL 4000 /* allows for 1000 personal types*/ #define TYPE_DISEASE 5000 /* allows for 1000 racial types */ The first 1000 sn's are reserved for spells, skills, weapons and tongues, occuring before TYPE_HIT ( 0 to 999 ) Then 1000 through 1999 are reserved for weapontypes for use in damage(). This is far more than anyone will ever need, but was probably done to keep things rounded out. Next we have 2000 through 2999 which is an entire partition of its own dedicated to the herb_table, and it continues like this down through the 5000 range. Each portion of these is stored in it's own array: extern SKILLTYPE * skill_table [MAX_SKILL]; extern SKILLTYPE * herb_table [MAX_HERB]; extern SKILLTYPE * disease_table [MAX_DISEASE]; (See also:) #define MAX_SKILL 500 #define MAX_HERB 20 #define MAX_DISEASE 20 You'll note skills only take up 500 of their 1000 slots, so if you ever approach the 500 limit you'll need to expand yours to the full 1000. If you ever approach that, you'll need to adjust all of the tables upwards to accomodate the number of skills you will really be having, like so: #define MAX_SKILL 5000 and #define TYPE_HIT 5000 /* allows for 5000 skills/spells */ #define TYPE_HERB 6000 /* allows for 1000 attack types */ #define TYPE_PERSONAL 7000 /* allows for 1000 herb types */ #define TYPE_RACIAL 9000 /* allows for 1000 personal types*/ #define TYPE_DISEASE 9000 /* allows for 1000 racial types */ Keep in mind not to boost yours too much higher than you will actually need, because every empty skill in a table is almost 4K of wasted memory. When the MUD loads up, it loads in all skills into their array, then it sorts them. It sorts them based on category, as well by name. This is how the practice list is divided into the sections it's in. Because the skill table itself is divided into those sections. If you've ever noticed, when you add a new skill, it appears at the end of the skill list until you reboot and this sorting takes place, and can't be used until then. This is because until it's in the appropriate place it can't be found. When a player begins looking for a skill or spell, or whatever, based on the type of skill, the mud searches through a specific portion of the skill table looking for it. There are several helper functions for this: find_spell, find_skill, find_weapon, find_tongue Each of these looks through just it's portion of the skill list to try to find the sn of a skill of that type, with the given name. On to the how... extern sh_int gsn_first_spell; extern sh_int gsn_first_skill; extern sh_int gsn_first_weapon; extern sh_int gsn_first_tongue; extern sh_int gsn_top_sn; These are used to keep track of boundaries. Refer to skill_types above (first enum) Spells move into Skills which move into Weapons which move into Tongues... Just like the order of the practice list. After sorting, the first of each type is identified, and from that point on the MUD can be aware that all skills fall between: gsn_first_skill and gsn_first_weapon-1 This saves speed, by being logical. No point searching areas you know your target can't possibly be. In order to add a new skill to the skill_table, we need to insert it in the skill_types list, somewhere after skill_spell, and preferrably before skill_tongue Lets practice by creating a new type we'll call SKILL_BLANK in mud.h typedef enum { SKILL_UNKNOWN, SKILL_SPELL, SKILL_SKILL, SKILL_BLANK, SKILL_WEAPON, SKILL_TONGUE, SKILL_HERB, SKILL_RACIAL, SKILL_DISEASE } skill_types; Notice I've chosen to put it before weapons and after skills. So further down in mud.h before: extern sh_int gsn_first_weapon; add: extern sh_int gsn_first_blank; Note this location is not necessary, but helps as a quick mnemonic to remember where it occurs. Next in db.c before sh_int gsn_first_weapon; add sh_int gsn_first_blank; Then before gsn_first_weapon = 0; add gsn_first_blank = 0; Then before: else if ( !gsn_first_weapon && skill_table[x]->type == SKILL_WEAPON ) gsn_first_weapon = x; add else if ( !gsn_first_blank && skill_table[x]->type == SKILL_BLANK ) gsn_first_blank = x; Now we move into magic.c and things get ugly: in: int skill_lookup( const char *name ) ***NOTE: What this function does, is go through each partition of the skil_table piece by piece, looking for an exact match to a skill name, then go through each portion again looking for the closest match (prefix). It returns the SN of the first match it finds, either way. Because you're changing boundaries, you need to rewrite the area it's looking, as well as add in handlers for the new boundaries. if ( (sn=bsearch_skill_exact(name, gsn_first_skill, gsn_first_weapon-1)) == -1 ) if ( (sn=bsearch_skill_exact(name, gsn_first_weapon, gsn_first_tongue-1)) == -1 ) becomes: if ( (sn=bsearch_skill_exact(name, gsn_first_skill, gsn_first_blank-1)) == -1 ) if ( (sn=bsearch_skill_exact(name, gsn_first_blank, gsn_first_weapon-1)) == -1 ) if ( (sn=bsearch_skill_exact(name, gsn_first_weapon, gsn_first_tongue-1)) == -1 ) And then: if ( (sn=bsearch_skill_prefix(name, gsn_first_skill, gsn_first_weapon-1)) == -1 ) if ( (sn=bsearch_skill_prefix(name, gsn_first_weapon, gsn_first_tongue-1)) == -1 ) becomes: if ( (sn=bsearch_skill_prefix(name, gsn_first_skill, gsn_first_blank-1)) == -1 ) if ( (sn=bsearch_skill_prefix(name, gsn_first_blank, gsn_first_weapon-1)) == -1 ) if ( (sn=bsearch_skill_prefix(name, gsn_first_weapon, gsn_first_tongue-1)) == -1 ) Next we have to modify find_skill: return bsearch_skill( name, gsn_first_skill, gsn_first_weapon-1 ); else return ch_bsearch_skill( ch, name, gsn_first_skill, gsn_first_weapon-1 ); becomes: return bsearch_skill( name, gsn_first_skill, gsn_first_blank-1 ); else return ch_bsearch_skill( ch, name, gsn_first_skill, gsn_first_blank-1 ); You can create your own find_blank which you may or may not need depending on how you use this new skilltype: If you intend to use this new skill type like spells, via a nanny function ( do_blank, as opposed to do_cast ) you will need this. int find_blank( CHAR_DATA *ch, const char *name, bool know ) { if ( IS_NPC(ch) || !know ) return bsearch_skill( name, gsn_first_blank, gsn_first_weapon-1 ); else return ch_bsearch_skill( ch, name, gsn_first_blank, gsn_first_weapon-1 ); } Place a prototype of your do_blank in mud.h : before: int find_weapon args( ( CHAR_DATA *ch, const char *name, bool know ) ); add int find_blank args( ( CHAR_DATA *ch, const char *name, bool know ) ); Now on to saving and loading... save.c Before: case SKILL_WEAPON: fprintf( fp, "Weapon %d '%s'\n", ch->pcdata->learned[sn], skill_table[sn]->name ); break; add case SKILL_BLANK: fprintf( fp, "Blank %d '%s'\n", ch->pcdata->learned[sn], skill_table[sn]->name ); break; Down inside: if ( !strcmp( word, "Skill" ) ) change sn = bsearch_skill_exact( fread_word( fp ), gsn_first_skill, gsn_first_weapon-1 ); to sn = bsearch_skill_exact( fread_word( fp ), gsn_first_skill, gsn_first_blank-1 ); And in the case 'B' add in: if ( !strcmp( word, "Blank" ) ) { int sn; int value; if ( preload ) word = "End"; else { value = fread_number( fp ); if ( file_ver < 3 ) sn = skill_lookup( fread_word( fp ) ); else sn = bsearch_skill_exact( fread_word( fp ), gsn_first_blank, gsn_first_weapon-1 ); if ( sn < 0 ) bug( "Fread_char: unknown skill.", 0 ); else { ch->pcdata->learned[sn] = value; /* Take care of people who have stuff they shouldn't * * Assumes class and level were loaded before. -- Altrag * * Assumes practices are loaded first too now. -- Altrag */ if ( ch->level < LEVEL_IMMORTAL ) { if ( skill_table[sn]->skill_level[ch->class] >= LEVEL_IMMORTAL ) { ch->pcdata->learned[sn] = 0; ch->practice++; } } } fMatch = TRUE; break; } } in tables.c find char * const skill_tname[] = { "unknown", "Spell", "Skill", "Weapon", "Tongue", "Herb", "Racial", "Disease" }; and add in your new type: char * const skill_tname[] = { "unknown", "Spell", "Skill", "Blank", "Weapon", "Tongue", "Herb", "Racial", "Disease" }; Then in get_skill before if ( !str_cmp( skilltype, "Weapon" ) ) return SKILL_WEAPON; if ( !str_cmp( skilltype, "Blank" ) ) return SKILL_BLANK; Now we've reached what's essentially the hard part. Determiing how we will be using this new skill type. This depends on entirely on you , and how you want to use these. If this is going to be a type of skill where you want them to just type the name of the skill like: kick Then you will need to modify check_skill If you've followed my suggestion and placed the blank before weapon all you need to do is leave: int top = gsn_first_weapon-1; alone. If you DO NOT WANT them to be able to type these ala "kick" you will need to change that line to: int top = gsn_first_blank-1; As this is now where skills end. If you want your own customized "cast" for this skill type, you'll need to copy do_cast and rename it to your new command (do_blank or whatever) You'll want to customize all the messages it sends. And most importantly, you'll want to replace find_spell with find_blank in your do_blank as well as replace: if ( skill->type != SKILL_SPELL ) with if ( skill->type != SKILL_BLANK ) If you want this new category to contain nothing but 'passive' skills (like dodge/parry/2nd attack) that are only utilitized by existing, not by an action on behalf of the PC, you don't need a do_blank or to have it doable via check_skill, but odds are you'll want it to have both passive and one of the other types of active modes.