dawn/notes/
dawn/src/
dawn/src/docs/
/**************************************************************************/
// db2.cpp - 
/***************************************************************************
 * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt                    *
 * >> A number of people have contributed to the Dawn codebase, with the   *
 *    majority of code written by Michael Garratt - www.dawnoftime.org     *
 * >> To use this source code, you must fully comply with all the licenses *
 *    in licenses.txt... In particular, you may not remove this copyright  *
 *    notice.                                                              *
 ***************************************************************************
 * >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer,       *
 *    Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe.   *
 * >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael       *
 *    Chastain, Michael Quan, and Mitchell Tse.                            *
 * >> ROM 2.4 is copyright 1993-1995 Russ Taylor and has been brought to   *
 *    you by the ROM consortium: Russ Taylor(rtaylor@pacinfo.com),         *
 *    Gabrielle Taylor(gtaylor@pacinfo.com) & Brian Moore(rom@rom.efn.org) *
 * >> Oblivion 1.2 is copyright 1996 Wes Wagner                            *
 **************************************************************************/

#include "include.h" // dawn standard includes
#include "areas.h"
#include "db.h"

extern int flag_lookup args((const char *name, const struct flag_type *flag_table));
struct	social_old_type	social_table[MAX_SOCIALS];
int		social_count;

extern NOTE_DATA *anote_list;

/**************************************************************************/
// read in a socials file - old format
void oldload_socials( FILE *fp)
{
	social_count=0;
    for ( ; ; ) 
    {
		if(social_count+5>MAX_SOCIALS){
			logf("oldload_socials()... Too many socials read in from file... "
				"you should read in the ones you want, use importsocials to convert them "
				"to the new format, then remove the socials from the helpfile list.");
			exit_error( 1 , "oldload_socials", "Too many socials");
			return;
		}
    	struct social_old_type social;
    	char *temp;
        // clear social
		social.char_no_arg = NULL;
		social.others_no_arg = NULL;
		social.char_found = NULL;
		social.others_found = NULL;
		social.vict_found = NULL; 
		social.char_not_found = NULL;
		social.char_auto = NULL;
		social.others_auto = NULL;

	    temp = fread_word(fp);
		if (!strcmp(temp,"#0")){
			break; // done
		}
#if defined(social_debug) 
		else{
			logf("%s",temp);
		}
#endif

    	strcpy(social.name,temp);
    	fread_to_eol(fp);

	temp = fread_string_eol(fp);
	if (!strcmp(temp,"$"))
	     social.char_no_arg = NULL;
	else if (!strcmp(temp,"#"))
	{
	     social_table[social_count] = social;
	     social_count++;
	     continue; 
	}
        else
	    social.char_no_arg = temp;

        temp = fread_string_eol(fp);
        if (!strcmp(temp,"$"))
             social.others_no_arg = NULL;
        else if (!strcmp(temp,"#"))
        {
	     social_table[social_count] = social;
             social_count++;
             continue;
		  }
        else
	    social.others_no_arg = temp;

        temp = fread_string_eol(fp);
        if (!strcmp(temp,"$"))
             social.char_found = NULL;
        else if (!strcmp(temp,"#"))
        {
	     social_table[social_count] = social;
             social_count++;
             continue;
        }
       	else
	    social.char_found = temp;

        temp = fread_string_eol(fp);
        if (!strcmp(temp,"$"))
             social.others_found = NULL;
        else if (!strcmp(temp,"#"))
        {
	     social_table[social_count] = social;
             social_count++;
             continue;
		  }
        else
	    social.others_found = temp; 

        temp = fread_string_eol(fp);
        if (!strcmp(temp,"$"))
             social.vict_found = NULL;
        else if (!strcmp(temp,"#"))
        {
	     social_table[social_count] = social;
             social_count++;
             continue;
        }
        else
	    social.vict_found = temp;

        temp = fread_string_eol(fp);
        if (!strcmp(temp,"$"))
             social.char_not_found = NULL;
        else if (!strcmp(temp,"#"))
        {
	     social_table[social_count] = social;
             social_count++;
             continue;
		  }
        else
	    social.char_not_found = temp;

        temp = fread_string_eol(fp);
        if (!strcmp(temp,"$"))
             social.char_auto = NULL;
        else if (!strcmp(temp,"#"))
        {
	     social_table[social_count] = social;
             social_count++;
             continue;
        }
        else
	    social.char_auto = temp;
         
        temp = fread_string_eol(fp);
        if (!strcmp(temp,"$"))
             social.others_auto = NULL;
        else if (!strcmp(temp,"#"))
        {
             social_table[social_count] = social;
             social_count++;
             continue;
		  }
        else
	    social.others_auto = temp; 
	
	social_table[social_count] = social;
    	social_count++;
   }

   logf("autonoting that old style social file was read in.");
   autonote(NOTE_SNOTE, "p_anote()", "remove oldstyle socials loading from files listed in helplist.txt", "admin", 
	   "Old style socials were loaded in from helplist.txt... you can import them using 'importsocials' "
	   "Once you have dealt with the issue of socials, remove the filename loading socials from helplist.txt... "
	   "You can usually find this helpfile(s) by typing 'grep SOCIALS *' in the help directory.", true);
   anote_list=NULL;

   return;
}

/**************************************************************************/
void load_mobiles( FILE *fp, int version )
{
	MOB_INDEX_DATA *pMobIndex;
	char *racename;
	
	if ( !area_last ){
		bug("Load_mobiles: no #AREA seen yet.");
		exit_error( 1 , "load_mobiles", "no #AREA seen yet");		
	}
	
	for ( ; ; )
	{
		vn_int vnum;
		char letter;
		int iHash;
		
		letter = fread_letter( fp );
		if ( letter != '#' )
		{
			bug("Load_mobiles: # not found.");
			exit_error( 1 , "load_mobiles", "# not found");
		}
		
		vnum = fread_number( fp );
		if ( vnum == 0 )
			break;
		vnum+= area_last->vnum_offset; 
		
		// make sure we don't have a duplicated mob vnum
		fBootDb = false;  // this is turned off to prevent logging of unfound vnums
		if ( get_mob_index( vnum ) ){
			char *aname="an unknown area.";
			if( get_mob_index( vnum )->area 
				&& get_mob_index( vnum )->area->file_name){
				aname=get_mob_index( vnum )->area->file_name;
			}
			bugf( "load_mobiles: vnum %d duplicated.", vnum );
			logf("with %s (%s) from %s",
				get_mob_index( vnum )->short_descr,
				get_mob_index( vnum )->player_name,
				aname);
			exit_error( 1 , "load_mobiles", "duplicate vnum");
		}
		fBootDb = true;
		
		last_vnum = vnum; // backup the last vnum for gdb use 
		
		pMobIndex= (MOB_INDEX_DATA *)alloc_perm( sizeof(*pMobIndex) );
		pMobIndex->vnum	= vnum;
		pMobIndex->area	= area_last;
		pMobIndex->xp_mod= 100; // default value		

		// check mob vnum fits in areas vnum range 
		if ( vnum < pMobIndex->area->min_vnum + pMobIndex->area->vnum_offset)
		{
			bugf("Mob with Vnum %d is less than area %s <%s> vnum %d!",
				vnum,
				pMobIndex->area->name,
				pMobIndex->area->file_name,
				pMobIndex->area->min_vnum
				);
		}
		if ( vnum > pMobIndex->area->max_vnum + pMobIndex->area->vnum_offset)
		{
			bugf("Mob with Vnum %d is greater than area %s <%s> vnum %d!",
				vnum,
				pMobIndex->area->name,
				pMobIndex->area->file_name,
				pMobIndex->area->max_vnum
				);
		}
		
		pMobIndex->player_name			= fread_string( fp );
		pMobIndex->short_descr			= fread_string( fp );
		pMobIndex->long_descr			= trim_trailing_carriage_return_line_feed(fread_string( fp ));
		pMobIndex->description			= fread_string( fp );

		if (str_len(pMobIndex->description)>MSL-4)
		{
			bugf("load_mobiles: Description of mob %d is %d characters!!!"
				"(more than %d)",
				(int)last_vnum, str_len(pMobIndex->description), MSL-4);
			exit_error( 1 , "load_mobiles", "description too long");
		}
		pMobIndex->long_descr[0]		= UPPER(pMobIndex->long_descr[0]);
		pMobIndex->description[0]		= UPPER(pMobIndex->description[0]);

		racename						= fread_string( fp );
		pMobIndex->race					= race_lookup(racename);
		if(pMobIndex->race == -1)
		{
			logf("Mob with Vnum %d has an unrecognised race '%s', "
				"dynamically generating a race.", vnum, racename);
			pMobIndex->race= race_generate_race_adding_to_race_table(racename);
		}
		free_string(racename);

		// count all the usage stats while loading
		race_table[pMobIndex->race]->inuse++;
		total_npcracescount++;
		if (race_table[pMobIndex->race]->lastarea!=area_last){
			race_table[pMobIndex->race]->areacount++;
			total_npcareacount++;
		}
		race_table[pMobIndex->race]->lastarea=area_last;
		
		pMobIndex->act					= fread_flag( fp ) | ACT_IS_NPC
										| race_table[pMobIndex->race]->act;

		if(AREA_IMPORT_FORMAT(AIF_FORMAT2)){
			areaimport_mobile_affects_format2(fp, version, pMobIndex);
		}else{
			// AIF_STOCK - the default
			areaimport_mobile_affects_stock(fp, version, pMobIndex);
		}

		pMobIndex->pShop				= NULL;

		// get alliance and tendency
		switch(version){
			case 1:
				{
					int talign					= fread_number( fp );
					pMobIndex->tendency			= number_range(1,7)-4;
					pMobIndex->alliance			= (3*talign)/1000;
					pMobIndex->group			= fread_number( fp );
				}
				break;

			case 2:
				pMobIndex->tendency         = fread_number( fp );
				pMobIndex->alliance         = fread_number( fp );
				break;

			default:
				pMobIndex->tendency 			= fread_number( fp );
				pMobIndex->alliance 			= fread_number( fp );
				pMobIndex->xp_mod				= fread_number( fp );
				if (pMobIndex->xp_mod<0 || pMobIndex->xp_mod>500){
					bugf( "Load_mobiles: mob vnum %d, XP_MOD is %d (>500 or <0!)", 
						vnum, pMobIndex->xp_mod);
				}		
				break;
		}

		pMobIndex->level				= fread_number( fp );
		pMobIndex->hitroll				= fread_number( fp );
		
		/* read hit dice */
		pMobIndex->hit[DICE_NUMBER] 	= fread_number( fp );
		/* 'd'			*/				  fread_letter( fp );
		pMobIndex->hit[DICE_TYPE]		= fread_number( fp );
		/* '+'			*/				  fread_letter( fp );
		pMobIndex->hit[DICE_BONUS]		= fread_number( fp );
		
		/* read mana dice */
		pMobIndex->mana[DICE_NUMBER]	= fread_number( fp );
		/* 'd'			*/				  fread_letter( fp );
		pMobIndex->mana[DICE_TYPE]		= fread_number( fp );
		/* '+'			*/				  fread_letter( fp );
		pMobIndex->mana[DICE_BONUS] 	= fread_number( fp );

		/* read damage dice */
		pMobIndex->damage[DICE_NUMBER]	= fread_number( fp );
		/* 'd'			*/				  fread_letter( fp );
		pMobIndex->damage[DICE_TYPE]	= fread_number( fp );
		/* '+'			*/				  fread_letter( fp );
		pMobIndex->damage[DICE_BONUS]	= fread_number( fp );
		pMobIndex->dam_type 			= attack_lookup(fread_word(fp));
		
		// read armor class 
		if(version<6){
			pMobIndex->ac[AC_PIERCE]		= fread_number( fp ) * 10;
			pMobIndex->ac[AC_BASH]			= fread_number( fp ) * 10;
			pMobIndex->ac[AC_SLASH] 		= fread_number( fp ) * 10;
			pMobIndex->ac[AC_EXOTIC]		= fread_number( fp ) * 10;
		}else{
			pMobIndex->ac[AC_PIERCE]		= fread_number( fp );
			pMobIndex->ac[AC_BASH]			= fread_number( fp );
			pMobIndex->ac[AC_SLASH] 		= fread_number( fp );
			pMobIndex->ac[AC_EXOTIC]		= fread_number( fp );
		}
		
		// read flags and add in data from the race table 
		pMobIndex->off_flags			= fread_flag( fp )
										| race_table[pMobIndex->race]->off;
		pMobIndex->imm_flags			= fread_flag( fp )
										| race_table[pMobIndex->race]->imm;
		pMobIndex->res_flags			= fread_flag( fp )
										| race_table[pMobIndex->race]->res;
		pMobIndex->vuln_flags			= fread_flag( fp )
										| race_table[pMobIndex->race]->vuln;
		
		// vital statistics 
		pMobIndex->start_pos			= position_lookup(fread_word(fp));
		if (pMobIndex->start_pos==-1){
			bugf("load_mobiles: mob %d (%s) start position is invalid!",
				(int)last_vnum, pMobIndex->short_descr);
			exit_error( 1 , "load_mobiles", "invalid start position");
		}
		
		pMobIndex->default_pos			= position_lookup(fread_word(fp));
		if (pMobIndex->default_pos==-1){
			bugf("load_mobiles: mob %d (%s) default position is invalid!",
				(int)last_vnum, pMobIndex->short_descr);
			exit_error( 1 , "load_mobiles", "invalid default position");
		}
		
		pMobIndex->sex					= sex_lookup(fread_word(fp));
		if (pMobIndex->sex==-1){
			bugf("load_mobiles: mob %d (%s) sex category doesn't exist!",
				(int)last_vnum, pMobIndex->short_descr);
			exit_error( 1 , "load_mobiles", "invalid sex");
		}
		
		pMobIndex->wealth				= fread_number( fp );

		if (pMobIndex->wealth<0){
			bugf("load_mobiles: mob %d (%s) wealth is less than 0!",
				(int)last_vnum, pMobIndex->short_descr);
			exit_error( 1 , "load_mobiles", "negative wealth");
		}
		
		if(pMobIndex->wealth > pMobIndex->level*10){
			pMobIndex->wealth=pMobIndex->level*10;
		}
		
		
		pMobIndex->form 				= fread_flag( fp )
										| race_table[pMobIndex->race]->form;
		pMobIndex->parts				= fread_flag( fp )
										| race_table[pMobIndex->race]->parts;
		// size 
		pMobIndex->size 				= size_lookup(fread_word(fp));

		// material
		pMobIndex->material 			= str_dup(lowercase(fread_word( fp )));
		if(!str_cmp(pMobIndex->material,"0")){
			replace_string(pMobIndex->material,"unknown");
		}

		
		for ( ; ; )
		{
			letter = fread_letter( fp );

			if (letter == 'G') // read their group (if they have one)
			{
				char *word= fread_word(fp);
				if(is_number(word)){
					pMobIndex->group=atoi(word);
				}else{
					bugf("Unexpected input in loading mobile %d's group number "
						"- must be numeric 'G %s'", pMobIndex->vnum, word);
					exit_error( 1 , "load_mobiles", "unexpected group number input");
				}
			}
			else if (letter == 'H') // read their helpgroup (if they have one)
			{
				char *word= fread_word(fp);
				if(is_number(word)){
					pMobIndex->helpgroup=atoi(word);
				}else{
					bugf("Unexpected input in loading mobile %d's helpgroup number "
						"- must be numeric 'H %s'", pMobIndex->vnum, word);
					exit_error( 1 , "load_mobiles", "unexpected helpgroup number input");
				}
			}
			else if (letter == 'F')
			{
				char *word;
				long vector;
				
				word					= fread_word(fp);
				vector					= fread_flag(fp);
				
				if (!str_prefix(word,"act"))
					REMOVE_BIT(pMobIndex->act,vector);
				else if (!str_prefix(word,"aff"))
					REMOVE_BIT(pMobIndex->affected_by,vector);
				else if (!str_prefix(word,"off"))
					REMOVE_BIT(pMobIndex->affected_by,vector);
				else if (!str_prefix(word,"imm"))
					REMOVE_BIT(pMobIndex->imm_flags,vector);
				else if (!str_prefix(word,"res"))
					REMOVE_BIT(pMobIndex->res_flags,vector);
				else if (!str_prefix(word,"vul"))
					REMOVE_BIT(pMobIndex->vuln_flags,vector);
				else if (!str_prefix(word,"for"))
					REMOVE_BIT(pMobIndex->form,vector);
				else if (!str_prefix(word,"par"))
					REMOVE_BIT(pMobIndex->parts,vector);
				else
				{
					bugf("load_mobiles: flag '%s' not found.", word);
					exit_error( 1 , "load_mobiles", "flag not found");
				}
			}
			else if ( letter == 'M' )
			{
				MPROG_LIST *pMprog;
				char *word;
				int trigger = 0;
				
				pMprog		   = (MPROG_LIST *)alloc_perm(sizeof(*pMprog));
				word		   = fread_word( fp );

				// support position flags
				if(word[0]=='='){ 
					pMprog->pos_flags= fread_flag(fp);
					word= fread_word( fp );
				}

				if ( !(trigger = flag_lookup( word, mprog_flags )) )
				{
					bug("load_mobiles: invalid mobprog trigger.");
					exit_error( 1 , "load_mobiles", "invalid mobprog trigger");
				}
				SET_BIT( pMobIndex->mprog_flags, trigger );
				pMprog->trig_type	= trigger;

				// get the mobprog number, with vnum translation support
				int mpvnum=fread_number( fp );
				apply_area_vnum_offset( &mpvnum); // this system only works within a particular area
				pMprog->temp_mpvnum	= mpvnum; // hack for loading - fixed up in fix_mobprogs

				pMprog->trig_phrase = fread_string( fp );
				pMprog->next		= pMobIndex->mprogs;
				pMobIndex->mprogs	= pMprog;
			}		
			else
			{
				ungetc(letter,fp);
				break;
			}
		}
		
		iHash					= vnum % MAX_KEY_HASH;
		pMobIndex->next 		= mob_index_hash[iHash];
		mob_index_hash[iHash]	= pMobIndex;
		top_mob_index++;
		kill_table[URANGE(0, pMobIndex->level, MAX_LEVEL-1)].number++;

		// linked list of all pMobIndex records
		pMobIndex->listnext=pMobIndexlist;
		pMobIndexlist=pMobIndex;
	}
	return;
}


/**************************************************************************/
/**************************************************************************/
// Snarf an obj section
void load_objects( FILE *fp, int version )
{
	OBJ_INDEX_DATA *pObjIndex;
	
	if ( !area_last ){
		bug("Load_objects: no #AREA seen yet.");
		exit_error( 1 , "load_objects", "no #AREA seen yet");
	}
	
	for ( ; ; )
	{
		vn_int vnum;
		char letter;
		int iHash;
		
        letter = fread_letter( fp );
        if ( letter != '#' )
        {
            bug("Load_objects: # not found.");
            exit_error( 1 , "load_objects", "# not found");
        }
		
        vnum = fread_number( fp );
		if ( vnum == 0 )
            break;
		vnum+= area_last->vnum_offset; 
		
        fBootDb = false; // put here because get_obj_index() calls bug()
        if ( get_obj_index( vnum ) )
        {
			char *aname="an unknown area.";
			if(get_obj_index( vnum )->area 
				&& get_obj_index( vnum )->area->file_name){
				aname=get_obj_index( vnum )->area->file_name;
			}
            bugf( "Load_objects: vnum %d duplicated.", vnum );

			logf("with %s from %s",
				get_obj_index( vnum )->short_descr,
				aname);
			exit_error( 1 , "load_objects", "duplicate vnum");
		}
        fBootDb = true;
		
        last_vnum = vnum; // backup the last vnum for gdb use
		
        pObjIndex = (OBJ_INDEX_DATA *)alloc_perm( sizeof(*pObjIndex) );
        pObjIndex->vnum = vnum;
        pObjIndex->area = area_last;

        // check object vnum fits in areas vnum range 
        if ( vnum < pObjIndex->area->min_vnum + pObjIndex->area->vnum_offset)
        {
            bugf("Object with Vnum %d is less than area %s <%s> vnum %d!",
                vnum,
                pObjIndex->area->name,
                pObjIndex->area->file_name,
                pObjIndex->area->min_vnum
                );
        }
        if ( vnum > pObjIndex->area->max_vnum + pObjIndex->area->vnum_offset)
        {
            bugf("Object with Vnum %d is greater than area %s <%s> vnum %d!",
                vnum,
                pObjIndex->area->name,
                pObjIndex->area->file_name,
                pObjIndex->area->max_vnum
                );
        }
		
		
        pObjIndex->reset_num            = 0;
        pObjIndex->name                 = fread_string( fp );
        pObjIndex->short_descr          = fread_string( fp );
        pObjIndex->description          = fread_string( fp );
		{
			char * pStr					= fread_string( fp );
			pObjIndex->material         = str_dup(lowercase(pStr));
			free_string(pStr);
		}
		
		char *itypeword=fread_word( fp );
        pObjIndex->item_type            = item_lookup(itypeword);
		if(pObjIndex->item_type<1){
			bugf("Unrecognised item type '%s' for object %d", itypeword, pObjIndex->vnum);
			exit_error( 1 , "load_objects", "unrecognised item type");
		}
        pObjIndex->extra_flags          = fread_flag( fp );
		if ( version > 3 )
		{
			pObjIndex->extra2_flags		= fread_flag( fp );

			// Traps loading code here
			if ( IS_SET( pObjIndex->extra2_flags, OBJEXTRA2_TRAP ))
			{
				pObjIndex->trap_trig	= fread_number( fp );
				pObjIndex->trap_dtype	= fread_number( fp );
				pObjIndex->trap_charge	= fread_number( fp );
				pObjIndex->trap_modifier= fread_number( fp );
			}
			else // initialize it to zero to be thorough
			{
				pObjIndex->trap_trig	= 0;
				pObjIndex->trap_dtype	= 0;
				pObjIndex->trap_charge	= 0;
				pObjIndex->trap_modifier= 0;
			}
		}
        pObjIndex->wear_flags           = fread_flag( fp );
		
		if(AREA_IMPORT_FORMAT(AIF_FORMAT2)){
			areaimport_object_translate_flags_format2(fp, version, pObjIndex);
		}else if(AREA_IMPORT_FORMAT(AIF_FORMAT2)){
			areaimport_object_translate_flags_format3(fp, version, pObjIndex);
		}else{
			// AIF_STOCK - the default
			areaimport_object_translate_flags_stock(fp, version, pObjIndex);
		}

		load_object_values( fp, version, pObjIndex);

        pObjIndex->level                = fread_number( fp );
        pObjIndex->weight               = fread_number( fp );
        pObjIndex->cost                 = fread_number( fp );
		
        // condition
        letter                          = fread_letter( fp );
        switch (letter)
        {
		case ('P') :           pObjIndex->condition = 100; break;
		case ('G') :           pObjIndex->condition =  90; break;
		case ('A') :           pObjIndex->condition =  75; break;
		case ('W') :           pObjIndex->condition =  50; break;
		case ('D') :           pObjIndex->condition =  25; break;
		case ('B') :           pObjIndex->condition =  10; break;
		case ('R') :           pObjIndex->condition =   1; break;
		default:               pObjIndex->condition = 100; break;
        }
		if( version<2){
			pObjIndex->absolute_size=pObjIndex->weight;
			pObjIndex->relative_size=50;
		}else{				
			pObjIndex->absolute_size = fread_number(fp);
			pObjIndex->relative_size = fread_number(fp);		
		}

		if( version<3){
			pObjIndex->class_allowances = 0; 
		}else{
			if(version<5){
				int tempint= (sh_int)fread_flag(fp);
				// convert the class restriction into the allowance counter part
				if(tempint){		
					pObjIndex->class_allowances=~tempint;
					pObjIndex->class_allowances=tempint&0x1FF; // only the relevant bits
				}
			}
		}
		
        // optional parameters
		for ( ; ; )
        {
            char letter;
			
            letter = fread_letter( fp );
			if ( letter == 'A'){
				AFFECT_DATA *paf;
				paf                     = (AFFECT_DATA *)alloc_perm( sizeof(*paf) );
				paf->where              = WHERE_OBJEXTRA;
				paf->type               = -1;
				paf->level              = pObjIndex->level;
				paf->duration           = -1;
				paf->location           = translate_old_apply_number(fread_number( fp ));
				paf->modifier           = fread_number( fp );
				paf->bitvector          = 0;
				paf->next               = pObjIndex->affected;
				pObjIndex->affected     = paf;
				top_affect++;

				// convert to WHERE_MODIFIER if appropriate
				if(version==2){
					if(paf->location!=APPLY_NONE){
						paf->where=WHERE_MODIFIER;		
					}
					if(paf->location==1){
						paf->modifier=paf->modifier*2;
					}else if(paf->location==2){
						paf->modifier=paf->modifier*2;
						paf->location=APPLY_RE;  
					}else if(paf->location==3){
						paf->modifier=paf->modifier*2;
						paf->location=APPLY_ME;
					}else if(paf->location==4){
						paf->modifier=paf->modifier*2;
						paf->location=APPLY_QU;
					}else if(paf->location==5){
						paf->modifier=paf->modifier*2;
						paf->location=APPLY_CO;
					}else if(paf->location==APPLY_HIT){
						paf->modifier=paf->modifier/3;
					}
				}

			}else if (letter == 'B'){
				AFFECT_DATA *paf;
				paf                     = (AFFECT_DATA *)alloc_perm( sizeof(*paf) );
				paf->where              = WHERE_OBJEXTRA2;
				paf->type               = -1;
				paf->level              = pObjIndex->level;
				paf->duration           = -1;
				paf->location           = translate_old_apply_number(fread_number( fp ));
				paf->modifier           = fread_number( fp );
				paf->bitvector          = 0;
				paf->next               = pObjIndex->affected;
				pObjIndex->affected     = paf;
				top_affect++;
			}else if ( letter == 'L' && AREA_IMPORT_FORMAT(AIF_FORMAT3)){ 
				// load percentage - ignored
				fread_number(fp);
			}else if ( letter == 'C' || letter == '_'){ 
				if(letter == 'C' && AREA_IMPORT_FORMAT(AIF_FORMAT3)){
	                fread_string(fp); // a clan field
				}else{
    				if(letter == '_'){ // the _ so we can eventually remove the classrestrict
						fread_letter( fp ); // C
						fread_letter( fp ); // A
					}
					pObjIndex->class_allowances=fread_wordflag(classnames_flags, fp);
				}
			}else if ( letter == 'R' ){
				// format of R optional object line - class groups restrictions
				// R [classgroup_restriction] [affectprofile] [priority] [flags]
                OBJRESTRICT_LIST_DATA *pr;
				classgroup_type * cg;
				affectprofile_type *ap;

				char * classgroup	=fread_word ( fp );
				char * affectprofile=fread_word ( fp );
				int priority=fread_number( fp );
				int flags=fread_flag( fp );
				flags=0; // to get rid of compiler warning :)

				cg=classgroup_lookup(classgroup);
				ap=affectprofile_lookup(affectprofile);
				if(!cg || !ap){
					if(!cg){
						bugf("Unknown classgroup '%s' for object vnum %d restriction, IGNORING!", 
							classgroup, vnum);
					}
					if(!ap){
						bugf("Unknown affectprofile '%s' for object vnum %d restriction, IGNORING!", 
							affectprofile, vnum);
					}
				}else{
					pr=new OBJRESTRICT_LIST_DATA;
					pr->affectprofile=ap;
					pr->classgroup=cg;
					pr->priority=priority;
					// can't have positive affect modifiers 
					if(ap->wear_amount>0){
						bugf("positive ap->wear_amount for %s, inverted.", ap->name);
						ap->wear_amount=0-ap->wear_amount;
					}		
					// Add it to the restricts list
					pr->next			= pObjIndex->restrict;
					pObjIndex->restrict	= pr;
					SET_BIT(pObjIndex->objrestrict,(1<<cg->bitindex)); // create bit quick lookup
				}
			}else if (letter == 'F'){
				AFFECT_DATA *paf=NULL;
				
                paf                     = (AFFECT_DATA *)alloc_perm( sizeof(*paf) );
                letter                  = fread_letter(fp);
                switch (letter)
                {
                case 'A':
                    paf->where          = WHERE_AFFECTS;
                    break;
                case 'B':
                    paf->where          = WHERE_AFFECTS2;
                    break;
                case 'I':
					paf->where          = WHERE_IMMUNE;
                    break;
				case 'K':
					paf->where			= WHERE_SKILLS;
					break;
                case 'R':
                    paf->where          = WHERE_RESIST;
                    break;
                case 'V':
					paf->where			= WHERE_VULN;
                    break;
				case 'Z':
					paf->where			= WHERE_OBJECTSPELL;
					break;
                default:
                    bugf( "Load_objects: Unknown where flag 'F %c'.", letter);
					exit_error( 1 , "load_objects", "unknown where flag");
                }

				if ( paf->where == WHERE_SKILLS )
				{
					char *skillname			= fread_word(fp);
					paf->type				= skill_lookup(skillname);
					if(paf->type<0){
						bugf("Unknown skillname '%s' found while reading area file.",
							skillname);
						exit_error( 1 , "load_objects", "unknown skill name");
					}
					paf->modifier			= fread_number( fp );
					paf->bitvector			= 0;
				} else if (paf->where == WHERE_OBJECTSPELL){
					paf->location			= APPLY_NONE;
					char *spellname			= fread_word(fp);
					paf->type				= skill_lookup(spellname);
					if(paf->type<0){
						bugf("Unknown spellname '%s' found while reading area file.",
							spellname);
						exit_error( 1 , "load_objects", "unknown spell name");
					}
					paf->level				= fread_number(fp);
					paf->duration			= fread_number(fp);
					paf->bitvector          = fread_flag(fp);
				}else {
					paf->type				= -1;
					paf->location           = translate_old_apply_number(fread_number(fp));
					paf->modifier           = fread_number(fp);
					if(version==1 && AREA_IMPORT_FORMAT(AIF_FORMAT2)){
						paf->bitvector          = fread_number(fp);
					}else{
						// AIF_STOCK - the default
						paf->bitvector          = fread_flag(fp);
					}
				}

				paf->duration				= -1;
	            paf->level					= pObjIndex->level;
				paf->next					= pObjIndex->affected;
			    pObjIndex->affected			= paf;
                top_affect++;

            }
		    // some muds have Z for object spells
		    else if ( letter == 'Z' )
			{
			    int sn;
			    AFFECT_DATA *paf;
				char *last_word;		    
			    paf                     = (AFFECT_DATA*) alloc_perm (sizeof (*paf));
				last_word=fread_word (fp);
			    sn = skill_lookup (last_word);
			    if (0 > sn)
				{
				    bugf("Load_objects: unknown spell '%s'.", last_word);
					exit_error( 1 , "load_objects", "unknown spell");
				}else{
					paf->type = sn;
				}
				paf->where				= WHERE_OBJECTSPELL;
			    paf->location			= APPLY_NONE;
			    paf->level              = fread_number (fp);
			    paf->duration           = fread_number (fp);
			    paf->modifier           = 0;
			    paf->bitvector          = 0;
				paf->next					= pObjIndex->affected;
			    pObjIndex->affected			= paf;
			}	
            else if ( letter == 'E' )
			{
				EXTRA_DESCR_DATA *ed;   
				
				ed                      = (EXTRA_DESCR_DATA *)alloc_perm( sizeof(*ed) );
				ed->keyword             = fread_string( fp );
				ed->description         = fread_string( fp );
				
				if (str_len(ed->description)>MSL-4 || str_len(ed->keyword)>MSL-4 )
				{
					bugf("load_objects_three: Extended description in object "
						"%d is %d characters!!! (more than %d)", 
						(int)last_vnum, str_len(ed->description), MSL-4);
					exit_error( 1 , "load_objects", "extended description too long");
				}
				
				// chop off the . if it starts with that (version 3 up)
				if (version>2 && ed->description[0]=='.')
				{
					char *temp_string;
					temp_string = str_dup(ed->description);
					free_string(ed->description);
					ed->description= str_dup(temp_string+1);
					free_string(temp_string);
				}
				ed->next                = pObjIndex->extra_descr;
				pObjIndex->extra_descr  = ed;
				top_ed++;
			}else{ // end of optional parameters
				ungetc( letter, fp );// most likely a # starting next object
                break;
            }
        }
		
        iHash                   = vnum % MAX_KEY_HASH;
        pObjIndex->next         = obj_index_hash[iHash];
        obj_index_hash[iHash]   = pObjIndex;
        top_obj_index++;
	}
	
    return;
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/