shadow/
shadow/data/command/
shadow/data/help/
shadow/data/religion/
shadow/data/skill/
/****************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,         *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.    *
 *									    *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael	    *
 *  Chastain, Michael Quan, and Mitchell Tse.				    *
 *																			*
 *  In order to use any part of this Merc Diku Mud, you must comply with	*
 *  both the original Diku license in 'license.doc' as well the Merc		*
 *  license in 'license.txt'.  In particular, you may not remove either of	*
 *  these copyright notices.												*
 *																			*
 *  Much time and thought has gone into this software and you are			*
 *  benefitting.  We hope that you share your changes too.  What goes		*
 *  around, comes around.													*
 ***************************************************************************/
 
/****************************************************************************
*	ROM 2.4 is copyright 1993-1998 Russ Taylor								*
*	ROM has been brought to you by the ROM consortium						*
*	    Russ Taylor (rtaylor@hypercube.org)									*
*	    Gabrielle Taylor (gtaylor@hypercube.org)							*
*	    Brian Moore (zump@rom.org)											*
*	By using this code, you have agreed to follow the terms of the			*
*	ROM license, in the file Rom24/doc/rom.license							*
***************************************************************************/


#if defined(macintosh)
#include <types.h>
#elif defined(WIN32)
#include <sys/types.h>
#include <time.h>
#define NOCRYPT
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "merc.h"
#include "interp.h"
#include "magic.h"
#include "recycle.h"
#include "tables.h"
#include "lookup.h"
#include "olc.h"
#include "const.h"

int const_lookup args ( (const char *name ) );

#define DIF(a,b) (~((~a)|(b)))
/*stuff to set up key*/
#define KEY( literal, field, value ) if ( !str_cmp( word, literal ) ) 	{  field  = value;   fMatch = TRUE;	break; 	}

/* provided to free strings */
#if defined(KEYS)
#undef KEYS
#endif

#define KEYS( literal, field, value ) if ( !str_cmp( word, literal ) )	{   free_string(field);  field  = value; fMatch = TRUE; break;	}
/*end stuff for key*/

/*****************************************************************************
 Name:		fwrite_rooms
 Purpose:	Save #ROOMS section of an area file.
 Called by:	save_area(olc_save.c).
 ****************************************************************************/
void fwrite_rooms( FILE *fp, AREA_DATA *pArea )
{
    ROOM_INDEX_DATA *pRoomIndex;
    EXTRA_DESCR_DATA *pEd;
    EXIT_DATA *pExit;
    int iHash;
    int door;
	PROG_LIST *pRprog;
	char buf[MSL];

    fprintf( fp, "#ROOMSNEW\n" );
    for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
    {
        for( pRoomIndex = room_index_hash[iHash]; pRoomIndex; pRoomIndex = pRoomIndex->next )
        {
            if ( pRoomIndex->area == pArea )
            {
				fprintf( fp, "#ROOM\n" );
                fprintf( fp, "Vnum %d\n",		pRoomIndex->vnum );
                fprintf( fp, "Name %s~\n",		pRoomIndex->name );
                fprintf( fp, "Desc %s~\n",		fix_string( pRoomIndex->description ) );
                fprintf( fp, "Room_flags %d\n",		pRoomIndex->room_flags );
                fprintf( fp, "Sector_type %d\n",		pRoomIndex->sector_type );
                fprintf ( fp, "X %d %d %d %d %d %d %d %d %d %d %d\n",
                                                                    pRoomIndex->mineral[MIN_STEEL],
                                                                    pRoomIndex->mineral[MIN_IRON],
                                                                    pRoomIndex->mineral[MIN_COPPER],
                                                                    pRoomIndex->mineral[MIN_ADAMANTIUM],
                                                                    pRoomIndex->mineral[MIN_PLATINUM],
                                                                    pRoomIndex->mineral[MIN_BRONZE],
                                                                    pRoomIndex->mineral[MIN_SILVER],
                                                                    pRoomIndex->mineral[MIN_MARBLE],
                                                                    pRoomIndex->mineral[MIN_BRASS],
                                                                    pRoomIndex->mineral[MIN_GRANITE],
                                                                    pRoomIndex->mineral[MIN_ELECTRUM]);

                for ( pEd = pRoomIndex->extra_descr; pEd;
                      pEd = pEd->next )
                {
					fprintf( fp, "ExtraDesc\n");
					fprintf( fp, "%s~\n",pEd->keyword );
                    fprintf( fp, "%s~\n", fix_string( pEd->description ) );
                }
                for( door = 0; door < MAX_DIR; door++ )	/* I hate this! */
                {
                    if ( ( pExit = pRoomIndex->exit[door] )
                          && pExit->u1.to_room )
                    {
                        fprintf( fp, "Exit\n");
						fprintf( fp, "%d\n",	pExit->orig_door );
                        fprintf( fp, "%s~\n",	fix_string( pExit->description ) );
                        fprintf( fp, "%s~\n",	pExit->keyword );
						fprintf( fp, "%d\n",	pExit->key);
                        fprintf( fp, "%d\n",	pExit->u1.to_room->vnum );
						fprintf( fp, "%s\n",	fwrite_flag(pExit->exit_info, buf) );
                    }
		    if( pExit && !pExit->u1.to_room && pExit->to_shaft )
			fwrite_mine( pExit, fp );
                }
				if (pRoomIndex->mana_rate != 100 || pRoomIndex->heal_rate != 100){
				 fprintf ( fp, "ManaRate %d\n",pRoomIndex->mana_rate);
				 fprintf ( fp, "HealRate %d\n", pRoomIndex->heal_rate);
				}
				for (pRprog = pRoomIndex->rprogs; pRprog; pRprog = pRprog->next)
				{
					 fprintf(fp, "R %s %d %s~\n",
					 prog_type_to_name(pRprog->trig_type), pRprog->vnum,
					 pRprog->trig_phrase);
				}
				fprintf( fp, "EndRoom\n\n" );
            }
        }
    }
    fprintf( fp, "#END\n\n\n\n" );
    return;
}

/*****************************************************************************
 Name:		fwrite_objects
 Purpose:	Save one object to file.
                new ROM format saving -- Hugin
 Called by:	save_objects (below).
 ****************************************************************************/
void fwrite_objects( FILE *fp, AREA_DATA *pArea )
{
    char letter;
    AFFECT_DATA *pAf;
    char buf[MAX_STRING_LENGTH];
	PROG_LIST *pOprog;
	OBJ_INDEX_DATA *pObjIndex;
	int i;
	EXTRA_DESCR_DATA *pEd;

    fprintf( fp, "#OBJECTSNEW\n" );

    for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
    {
		if ( (pObjIndex = get_obj_index( i )) )
		{
			fprintf( fp, "#OBJ\n" );
			fprintf( fp, "Vnum %d\n",    pObjIndex->vnum );
			fprintf( fp, "Name %s~\n",		pObjIndex->name );
			fprintf( fp, "Short %s~\n",    pObjIndex->short_descr );
			fprintf( fp, "Desc %s~\n",    fix_string( pObjIndex->description ) );
			fprintf( fp, "Material %s~\n",    pObjIndex->material );
			fprintf( fp, "Item_type %s\n",      item_name(pObjIndex->item_type));
			fprintf( fp, "Extra %s\n",    fwrite_flag( pObjIndex->extra_flags, buf ) );
                        fprintf( fp, "Extra2 %s\n",  print_flags( pObjIndex->extra2_flags) );     
			fprintf( fp, "Wear %s\n",     fwrite_flag( pObjIndex->wear_flags,  buf ) );

			/*
			 *  Using fwrite_flag to write mostValues gives a strange
			 *  looking area file, consider making a case for each
			 *  item type later.
			 */

			switch ( pObjIndex->item_type )
			{
				default:
				fprintf( fp, "Values %s ",  fwrite_flag( pObjIndex->value[0], buf ) );
				fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[1], buf ) );
				fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[2], buf ) );
				fprintf( fp, "%s ",  fwrite_flag( pObjIndex->value[3], buf ) );
				fprintf( fp, "%s\n", fwrite_flag( pObjIndex->value[4], buf ) );
				break;

				case ITEM_DRINK_CON:
				case ITEM_FOUNTAIN:
					fprintf( fp, "Values %d %d '%s' %d %d\n",
							 pObjIndex->value[0],
							 pObjIndex->value[1],
							 liq_table[pObjIndex->value[2]].liq_name,
					 pObjIndex->value[3],
					 pObjIndex->value[4]);
					break;


				case ITEM_CONTAINER:
					fprintf( fp, "Values %d %s %d %d %d\n",
                     pObjIndex->value[0],
                     fwrite_flag( pObjIndex->value[1], buf ),
                     pObjIndex->value[2],
                     pObjIndex->value[3],
                     pObjIndex->value[4]);
            break;

				case ITEM_WEAPON:
					 if(IS_WEAPON_STAT(pObjIndex,WEAPON_TWO_HANDS))
					 {
						 fprintf( fp, "Values %s %d %d %s %s\n",
							 weapon_name(pObjIndex->value[0]),
							 pObjIndex->value[1],
							 pObjIndex->value[2],
							 attack_table[pObjIndex->value[3]].name,
							 fwrite_flag( pObjIndex->value[4], buf ) );
					 }
					 else
					 {
						 fprintf( fp, "Values %s %d %d %s %s\n",
							 weapon_name(pObjIndex->value[0]),
							 pObjIndex->value[1],
							 pObjIndex->value[2],
							 attack_table[pObjIndex->value[3]].name,
							 fwrite_flag( pObjIndex->value[4], buf ) );
					 }
					break;
				case ITEM_PILL:
				case ITEM_POTION:
				case ITEM_SCROLL:
				fprintf( fp, "Values %d '%s' '%s' '%s' '%s'\n",
					 pObjIndex->value[0] > 0 ? /* no negative numbers */
					 pObjIndex->value[0]
					 : 0,
					 pObjIndex->value[1] != -1 ?
					 skill_table[pObjIndex->value[1]].name
					 : "",
					 pObjIndex->value[2] != -1 ?
					 skill_table[pObjIndex->value[2]].name
					 : "",
					 pObjIndex->value[3] != -1 ?
					 skill_table[pObjIndex->value[3]].name
					 : "",
					 pObjIndex->value[4] != -1 ?
					 skill_table[pObjIndex->value[4]].name
					 : "");
				break;

				case ITEM_STAFF:
				case ITEM_WAND:
				fprintf( fp, "Values %d %d %d '%s' %d\n",
	    					pObjIndex->value[0],
	    					pObjIndex->value[1],
	    					pObjIndex->value[2],
	    					pObjIndex->value[3] != -1 ?
	    						skill_table[pObjIndex->value[3]].name :
	    						"",
	    					pObjIndex->value[4] );
				break;

                case ITEM_BELT:
                case ITEM_SHEATH:
                        fprintf( fp, "%d %d %d %d\n", pObjIndex->value[0],
                                                pObjIndex->value[1],
                                                pObjIndex->value[2],
                                                pObjIndex->value[3]  );
                        break;
				case ITEM_QUIVER:
                        fprintf( fp, "%d ", pObjIndex->value[0] );
                        fprintf( fp, "%d ", pObjIndex->value[1] );
                        fprintf( fp, "%d 0 0\n", pObjIndex->value[2]);
                        break;

				case ITEM_ARROW:
                        fprintf( fp, "0 %d ", pObjIndex->value[1] );
                        fprintf( fp, "%d 0 0\n", pObjIndex->value[2]);
                        break;
				
			}

			fprintf( fp, "Level %d\n", pObjIndex->level );
			fprintf( fp, "Weight %d\n", pObjIndex->weight );
			fprintf( fp, "Cost %d\n", pObjIndex->cost );
                        fprintf( fp, "Plevel %d\n", pObjIndex->plevel );
                        fprintf( fp, "Exp %d\n", pObjIndex->exp );
                        fprintf( fp, "Xp_tolevel %d\n", pObjIndex->xp_tolevel );

				 if ( pObjIndex->condition >  90 ) letter = 'P';
			else if ( pObjIndex->condition >  75 ) letter = 'G';
			else if ( pObjIndex->condition >  50 ) letter = 'A';
			else if ( pObjIndex->condition >  25 ) letter = 'W';
			else if ( pObjIndex->condition >  10 ) letter = 'D';
			else if ( pObjIndex->condition >   0 ) letter = 'B';
			else                                   letter = 'R';

			fprintf( fp, "Condition %c\n", letter );
    			for( pEd = pObjIndex->extra_descr; pEd; pEd = pEd->next )
    			{
       			    fprintf( fp, "ExtraDesc\n%s~\n%s~\n", pEd->keyword,
                 	    fix_string( pEd->description ) );
    			}


			for( pAf = pObjIndex->affected; pAf; pAf = pAf->next )
			{
			if (pAf->where == TO_OBJECT || pAf->bitvector == 0)
					fprintf( fp, "AffectObj\n%d %d\n",  pAf->location, pAf->modifier );
			else
			{
				fprintf( fp, "F\n" );

				switch(pAf->where)
				{
					case TO_AFFECTS:
						fprintf( fp, "Faff " );
						break;
					case TO_IMMUNE:
						fprintf( fp, "Fimm " );
						break;
					case TO_RESIST:
						fprintf( fp, "Fres " );
						break;
					case TO_VULN:
						fprintf( fp, "Fvul " );
						break;
					default:
						bug( "olc_save: Invalid Affect->where", 0);
						break;
				}
				
				fprintf( fp, "%d %d %s\n", pAf->location, pAf->modifier,
						fwrite_flag( pAf->bitvector, buf ) );
			}
			}

			for (pOprog = pObjIndex->oprogs; pOprog; pOprog = pOprog->next)
			{
				fprintf(fp, "Oprg %s %d %s~\n",
				prog_type_to_name(pOprog->trig_type), pOprog->vnum,
						pOprog->trig_phrase);
			}
			fprintf( fp, "EndObj\n\n" );
}
}
	fprintf( fp, "#END\n\n\n\n" );
    return;
}
 
/*****************************************************************************
 Name:		fwrite_mobiles
 Purpose:	Save #MOBILES secion of an area file.
 Called by:	save_area(olc_save.c).
 Notes:         Changed for ROM OLC.
 ****************************************************************************/
void fwrite_mobiles( FILE *fp, AREA_DATA *pArea )
{
    int i;
    MOB_INDEX_DATA *pMobIndex;
    PROG_LIST *pMprog;
    char buf[MAX_STRING_LENGTH];
    long temp;

    fprintf( fp, "#MOBILESNEW\n" );

    for( i = pArea->min_vnum; i <= pArea->max_vnum; i++ )
    {
		if ( (pMobIndex = get_mob_index( i )) )
		{
			sh_int race = pMobIndex->race;
			fprintf( fp, "#MOB\n" );
			fprintf( fp, "Vnum %d\n",	pMobIndex->vnum );
			fprintf( fp, "Name %s~\n",	pMobIndex->player_name );
			fprintf( fp, "Short %s~\n",	pMobIndex->short_descr );
			fprintf( fp, "Long %s~\n",	fix_string( pMobIndex->long_descr ) );
			fprintf( fp, "Description %s~\n",	fix_string( pMobIndex->description) );
			fprintf( fp, "Race %s~\n",	race_table[race].name );
			fprintf( fp, "Act_flags %s\n",		fwrite_flag( pMobIndex->act,		buf ) );
			fprintf( fp, "Aff %s\n",		fwrite_flag( pMobIndex->affected_by,	buf ) );
			fprintf( fp, "Align %d\n",	pMobIndex->alignment);
			fprintf( fp, "Group %d\n", pMobIndex->group);
			fprintf( fp, "Level %d\n",		pMobIndex->level );
			fprintf( fp, "Hitroll %d\n",		pMobIndex->hitroll );
			fprintf( fp, "Hit_dice %ldd%ld+%ld\n",	pMobIndex->hit[DICE_NUMBER], 
						pMobIndex->hit[DICE_TYPE], 
						pMobIndex->hit[DICE_BONUS] );
			fprintf( fp, "Mana_dice %ldd%ld+%ld\n",	pMobIndex->mana[DICE_NUMBER], 
						pMobIndex->mana[DICE_TYPE], 
						pMobIndex->mana[DICE_BONUS] );
			fprintf( fp, "Dam_dice %dd%d+%d\n",	pMobIndex->damage[DICE_NUMBER], 
						pMobIndex->damage[DICE_TYPE], 
						pMobIndex->damage[DICE_BONUS] );
			fprintf( fp, "Dam_type %s\n",	attack_table[pMobIndex->dam_type].name );
			fprintf( fp, "Armor %d %d %d %d\n",
						pMobIndex->ac[AC_PIERCE] / 10, 
						pMobIndex->ac[AC_BASH]   / 10, 
						pMobIndex->ac[AC_SLASH]  / 10, 
						pMobIndex->ac[AC_EXOTIC] / 10 );
                        fprintf( fp, "Clevel%d\n",              pMobIndex->cast_level );
                        fprintf( fp, "Cability %d\n",           pMobIndex->cast_ability );
			fprintf( fp, "Off %s\n",		fwrite_flag( pMobIndex->off_flags,  buf ) );
			fprintf( fp, "Imm %s\n",		fwrite_flag( pMobIndex->imm_flags,  buf ) );
			fprintf( fp, "Res %s\n",		fwrite_flag( pMobIndex->res_flags,  buf ) );
			fprintf( fp, "Vuln %s\n",	fwrite_flag( pMobIndex->vuln_flags, buf ) );
			fprintf( fp, "Start_pos %s\n",	position_table[pMobIndex->start_pos].short_name);
			fprintf( fp, "Default_pos %s\n", position_table[pMobIndex->default_pos].short_name);
			fprintf( fp, "Sex %s\n",sex_table[pMobIndex->sex].name);
			fprintf( fp, "Wealth %ld\n",pMobIndex->wealth );
			fprintf( fp, "Form %s\n",		fwrite_flag( pMobIndex->form,  buf ) );
			fprintf( fp, "Parts %s\n",		fwrite_flag( pMobIndex->parts, buf ) );

			fprintf( fp, "Size %s\n",		size_table[pMobIndex->size].name );
			fprintf( fp, "Material %s\n",	IS_NULLSTR(pMobIndex->material) ? pMobIndex->material : "unknown" );
                        if ( pMobIndex->xp_tolevel >= 1000 )
                        fprintf( fp, "Xp_tolevel %d\n", pMobIndex->xp_tolevel);
                        fprintf( fp, "Aggression %d\n", pMobIndex->aggression );

			if ((temp = DIF(race_table[race].act,pMobIndex->act)))
     			fprintf( fp, "Fact %s\n", fwrite_flag(temp, buf) );

			if ((temp = DIF(race_table[race].aff,pMobIndex->affected_by)))
     			fprintf( fp, "Faff1 %s\n", fwrite_flag(temp, buf) );

			if ((temp = DIF(race_table[race].off,pMobIndex->off_flags)))
     			fprintf( fp, "Foff %s\n", fwrite_flag(temp, buf) );

			if ((temp = DIF(race_table[race].imm,pMobIndex->imm_flags)))
     			fprintf( fp, "Fimm %s\n", fwrite_flag(temp, buf) );

			if ((temp = DIF(race_table[race].res,pMobIndex->res_flags)))
     			fprintf( fp, "Fres %s\n", fwrite_flag(temp, buf) );

			if ((temp = DIF(race_table[race].vuln,pMobIndex->vuln_flags)))
     			fprintf( fp, "Fvul %s\n", fwrite_flag(temp, buf) );

			if ((temp = DIF(race_table[race].form,pMobIndex->form)))
     			fprintf( fp, "Ffor %s\n", fwrite_flag(temp, buf) );

			if ((temp = DIF(race_table[race].parts,pMobIndex->parts)))
    			fprintf( fp, "Fpar %s\n", fwrite_flag(temp, buf) );

			for (pMprog = pMobIndex->mprogs; pMprog; pMprog = pMprog->next)
			{
				fprintf(fp, "MobTrig %s %d %s~\n",
				prog_type_to_name(pMprog->trig_type), pMprog->vnum,
						pMprog->trig_phrase);
			}
			fprintf( fp, "EndMob\n\n" );
		}
	}

    fprintf( fp, "#END\n\n\n\n" );
    return;
}

/*****************************************************************************
 Name:		fwrite_area
 Purpose:	Save an area, note that this format is new.
 Called by:	do_asave(olc_save.c).
 ****************************************************************************/
void fwrite_area( AREA_DATA *pArea )
{
    FILE *fp = NULL;
	char buf[MSL];

    sprintf(buf, "%s%s", NEW_AREA_DIR,pArea->file_name);
	wiznet(buf,NULL,NULL,0,0,0);

    fp = file_open( buf, "w" );

    fprintf( fp, "#AREADATA\n" );
    fprintf( fp, "Name %s~\n",        pArea->name );
    fprintf( fp, "Builders %s~\n",        fix_string( pArea->builders ) );
    fprintf( fp, "VNUMs %d %d\n",      pArea->min_vnum, pArea->max_vnum );
    fprintf( fp, "Credits %s~\n",	 pArea->credits );
    fprintf( fp, "RepopMsg %s~\n",    pArea->repop_msg 	);
    fprintf( fp, "Security %d\n",         pArea->security );
    fprintf( fp, "Soundfile %s~\n",   pArea->soundfile );
    fprintf( fp, "Temps %d %d\n",     pArea->min_temp, pArea->max_temp );
    fprintf( fp, "Temperature %d\n",  pArea->temperature );
    fprintf( fp, "Continent %d\n", pArea->continent );
    fprintf( fp, "Levl %d %d\n", pArea->min_lev, pArea->max_lev );
    fprintf( fp, "End\n\n\n\n" );

    fwrite_mobiles( fp, pArea );
    fwrite_objects( fp, pArea );
    fwrite_rooms( fp, pArea );
    save_specials( fp, pArea );
    save_resets( fp, pArea );
    save_shops( fp, pArea );
    save_mobprogs( fp, pArea );
    save_objprogs( fp, pArea );
    save_roomprogs( fp, pArea );
    save_help_new(  );


    fprintf( fp, "#$\n" );

    file_close( fp );
    return;
}

void do_saveconst(CHAR_DATA *ch, char *argument )
{
    int i;
    FILE *fp = file_open("../data/const.txt", "w" );

    if(!fp)
	return;

    for(i = 0; const_table[i].name != NULL ; i++ )
        fprintf(fp, "%-30s %d\n",const_table[i].name, *const_table[i].value );
 
    fprintf(fp, "End\n");
    file_close(fp);
    return;
}

int const_lookup(const char *name )
{
     int i;
      for( i = 0; const_table[i].name != NULL ; i++ )
   	if(!str_cmp(name, const_table[i].name ) ) return i;
    return -1;
}

void load_const()
{
    FILE *fp;
    char *word;
    int i, value;
 
    if(!file_exists("../data/const.txt" ) )
    {  logf2("Constants do not exist! Find Davion and SLAY! SLAY!");
	return;
    }

    fp = file_open("../data/const.txt", "r" );

    for(;;)
    {  word = fread_word(fp);
	if(!str_cmp(word, "End" ) )
	     return;

	if( ( i = const_lookup(word) ) == -1 )
   	{    logf2("Invalid constant in const.txt!");
	     fread_number(fp);
	     continue;
        }
	value = fread_number(fp);
        *const_table[i].value = value;
    }
    file_close(fp);
    return;
}