/*
 *  Arcanum Editor - ROM area editor
 *  Copyright (C) 1999  Lucas Wall <kthulhu@usa.net>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *  If you make changes to the source and want to make the public you can
 *  mail the diferences to me <kthulhu@usa.net> and I'll add them to the
 *  main distribution. Of course your name will be added to the program with
 *  information about the changes you made.
 *
 *
 *  Packed on Thu Aug 19 03:02:28 1999
 *
 */


/*
 * File: arcaedDoc.cpp
 *
 * Changes:
 *
 * 19/08/99 Lucas Wall <kthulhu@usa.net>
 *          First source release. Its quite messy and has no
 *          comments. I never planed to release the source code... :-)
 *
 */


// arcaedDoc.cpp : implementation of the CArcaedDoc class
//

#include "stdafx.h"
#include "arcaed.h"

#include "arcaedDoc.h"
#include "RoomEd.h"
#include "fread.h"
#include "ObjEd.h"
#include "MobEd.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CArcaedDoc

IMPLEMENT_DYNCREATE(CArcaedDoc, CDocument)

BEGIN_MESSAGE_MAP(CArcaedDoc, CDocument)
	//{{AFX_MSG_MAP(CArcaedDoc)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CArcaedDoc construction/destruction

CArcaedDoc::CArcaedDoc()
{
	CNumStrData *data;

	m_builders = "";
	m_credits = "";
	m_maxvnum = 0;
	m_minvnum = 0;
	m_name = "";
	m_nivelmax = 0;
	m_nivelmin = 0;
	m_security = 0;
	m_map_maxlevel = m_map_minlevel = 0;
	for ( int i = 0; i < tables.m_recuname.GetSize(); i++ )
	{
		data = new CNumStrData();
		data->m_text = tables.m_recuname[i]->m_text;
		data->m_num = 0;
		m_recu.Add( data );
	}

	m_size = 12;
}

CArcaedDoc::~CArcaedDoc()
{
}

BOOL CArcaedDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	m_builders = "";
	m_credits = "Armada con ArcanumED por Kthulhu";
	m_maxvnum = 100;
	m_minvnum = 1;
	m_name = "Sin Nombre";
	m_nivelmax = 60;
	m_nivelmin = 1;
	m_security = 9;
	m_map_maxlevel = m_map_minlevel = 0;

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CArcaedDoc serialization

void CArcaedDoc::Serialize(CArchive& ar)
{
	CString word;

	if (ar.IsStoring())
	{
		// TODO: add storing code here

		MakeResetList();

		switch( tables.m_mudtype )
		{
		case MUD_ARCANUM: save_area( ar ); break;
		case MUD_ROMDEFAULT: save_areaold( ar ); break;
		case MUD_ROMOLC: save_area( ar ); break;
		}
		save_mobs( ar );
		save_objects( ar );
		save_rooms( ar );
		save_shops( ar );
		save_specials( ar );
		if ( tables.m_mobprog ) save_mobprog( ar );
		save_resets( ar );

		arprintf( ar, "#$\n" );

	}
	else
	{
		// TODO: add loading code here

		while ( true )
		{

			if ( fread_letter( ar ) != '#' ) return;
			word = fread_word( ar );
			word.MakeUpper();

			if ( word[0] == '$' ) break;
			else if ( word == "AREA" ) load_areaold( ar );
			else if ( word == "AREADATA" ) load_area( ar );
			else if ( word == "HELPS" ) load_help( ar );
			else if ( word == "MOBOLD" ) load_none( ar );
			else if ( word == "MOBILES" ) load_mobs( ar );
			else if ( word == "MOBPROGS" ) load_mobprog( ar );
			else if ( word == "OBJOLD" ) load_none( ar );
			else if ( word == "OBJECTS" ) load_objects( ar );
			else if ( word == "RESETS" ) load_resets( ar );
			else if ( word == "ROOMS" ) load_rooms( ar );
			else if ( word == "SHOPS" ) load_shops( ar );
			else if ( word == "SOCIALS" ) load_socials( ar );
			else if ( word == "SPECIALS" ) load_specials( ar );

		}
		AdjustMap( m_size );
		UpdateRoomResets();
	}
}

/////////////////////////////////////////////////////////////////////////////
// CArcaedDoc diagnostics

#ifdef _DEBUG
void CArcaedDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CArcaedDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CArcaedDoc commands

void CArcaedDoc::load_area(CArchive & ar)
{
	CString word;

	while ( true )
	{

		word = fread_word( ar );
		if ( word == "" ) word = "End";
		word.MakeUpper();

		switch( word[0] )
		{

		case 'N':
			if ( word == "NAME" )
			{
				m_name = fread_string( ar );
				break;
			}
			if ( word == "NIVELMAX" )
			{
				m_nivelmax = fread_number( ar );
				break;
			}
			if ( word == "NIVELMIN" )
			{
				m_nivelmin = fread_number( ar );
				break;
			}
			break;

		case 'B':
			if ( word == "BUILDERS" )
			{
				m_builders = fread_string( ar );
				break;
			}
			break;

		case 'V':
			if ( word == "VNUMS" )
			{
				m_minvnum = fread_number( ar );
				m_maxvnum = fread_number( ar );
				break;
			}
			break;

		case 'C':
			if ( word == "CREDITS" )
			{
				m_credits = fread_string( ar );
				break;
			}
			break;

		case 'S':
			if ( word == "SECURITY" )
			{
				m_security = fread_number( ar );
				break;
			}
			break;

		case 'E':
			if ( word == "END" )
			{
				return;
			}

		case 'R':
			if ( word == "RECURSO" )
			{
				int j = fread_number( ar );
				m_recu[j]->m_num = fread_number( ar );
				break;
			}

		}

	}
}

void CArcaedDoc::load_areaold(CArchive & ar)
{
	fread_string( ar );
	m_name = fread_string( ar );
	m_credits = fread_string( ar );
	m_minvnum = fread_number( ar );
	m_maxvnum = fread_number( ar );
}

void CArcaedDoc::load_rooms(CArchive & ar)
{
	int vnum, door, lock;
	CRoomData *room;
	CExtraDescr *extradescr;
	char c;

	while( true )
	{

		if ( fread_letter( ar ) != '#' )
			return;
		vnum = fread_number( ar );
		if ( !vnum ) break;

		room = new CRoomData();
		room->m_vnum = vnum;
		room->m_name = fread_string( ar );
		room->m_description = fread_string( ar );
		fread_number( ar );
		room->m_room_flags = fread_number( ar );
		room->m_sector_type = fread_number( ar );
		m_rooms.Add( room );

		while ( true )
		{

			c = toupper( fread_letter( ar )	);
			if ( c == 'S' || c == 0 ) break;
			switch ( c )
			{

			case 'E':
				extradescr = new CExtraDescr();
				extradescr->m_keyword = fread_string( ar );
				extradescr->m_description = fread_string( ar );
				room->m_extradescr.Add( extradescr );
				break;

			case 'D':
				door = fread_number( ar );
				ASSERT( door >= 0 && door <= 5 );
				room->m_exits[door].m_description = fread_string( ar );
				room->m_exits[door].m_keyword = fread_string( ar );
				lock = fread_number( ar );
				switch ( lock )
				{
				case 1: room->m_exits[door].m_flags = 1; break;
				case 2: room->m_exits[door].m_flags = 33; break;
				case 3: room->m_exits[door].m_flags = 65; break;
				case 4: room->m_exits[door].m_flags = 97; break;
				}
				room->m_exits[door].m_key = fread_number( ar );
				room->m_exits[door].m_vnum = fread_number( ar );
				break;

			case 'X':
				door = fread_number( ar );
				ASSERT( door >= 0 && door <= 5 );
				room->m_exits[door].m_flags = fread_flags( ar );
				break;

			case 'M':
				room->m_mana_rate = fread_number( ar );
				break;

			case 'H':
				room->m_heal_rate = fread_number( ar );
				break;

			case 'O':
				room->m_owner = fread_string( ar );
				break;

			case 'C':
				room->m_clan = fread_string( ar );
				break;

			}

		}

	}

}

void CArcaedDoc::load_none(CArchive & ar)
{
	char c;
	int num;

	while ( true )
	{
		while ( true )
		{
			c = fread_letter( ar );
			if ( c == '#' || c == 0 ) break;
		}
		num = fread_number( ar );
		if ( num == 0 ) break;
	}

}

void CArcaedDoc::load_help(CArchive & ar)
{
	CString string;
	int num;

	while ( true )
	{
		num = fread_number( ar );
		string = fread_number( ar );
		if ( string == "$" ) break;
		fread_string( ar );
	}

}

void CArcaedDoc::load_resets(CArchive & ar)
{
	CResetData *reset;
	char type;

	while ( true )
	{
		type = toupper( fread_letter( ar ) );
		if ( type == 'S' || type == 0 ) return;
		if ( type == '*' )
		{
			fread_eol( ar );
			continue;
		}

		reset = new CResetData();
		reset->m_type = type;
		fread_number( ar );
		reset->m_num[0] = fread_number( ar );
		reset->m_num[1] = fread_number( ar );
		if ( type != 'G' && type != 'R' )
			reset->m_num[2] = fread_number( ar );
		if ( type == 'P' || type == 'M' )
			reset->m_num[3] = fread_number( ar );
		m_resets.Add( reset );
	}

}

void CArcaedDoc::load_shops(CArchive & ar)
{
	CShopData *shop;
	int vnum;
	int i;
	CString text;

	while ( true )
	{
		text = fread_word( ar );
		if ( text == "*" )
		{
			fread_eol( ar );
			continue;
		}
		vnum = atoi( text.GetBuffer( 0 ) );
		if ( !vnum ) return;

		shop = new CShopData();
		for ( i = 0; i < 5; i++ )
			shop->m_trade[i] = fread_number( ar );
		shop->m_percent_buy = fread_number( ar );
		shop->m_percent_sell = fread_number( ar );
		shop->m_open_hour = fread_number( ar );
		shop->m_close_hour = fread_number( ar );

		if ( ( i = FindMob( vnum ) ) != -1 )
		{
			if ( m_mobs[i]->m_shopdata != NULL )
				delete m_mobs[i]->m_shopdata;
			m_mobs[i]->m_shopdata = shop;
		}
		else 
			delete shop;

	}

}

void CArcaedDoc::load_mobprog(CArchive & ar)
{
	CMobProgData *mobprog;
	int vnum, i;
	CString temp;

	while ( true )
	{
		if ( fread_letter( ar ) != '#' ) return;
		vnum = fread_number( ar );
		if ( !vnum ) return;

		mobprog = new CMobProgData();
		mobprog->m_vnum = vnum;
		temp = fread_string( ar, FALSE );
		mobprog->m_code = "";
		for ( i = 0; i < temp.GetLength(); i++ )
		{
			if ( temp[i] == '\n' )
				mobprog->m_code += '\r';
			mobprog->m_code += temp[i];
		}
		m_mobprogs.Add( mobprog );
	}

}

void CArcaedDoc::load_socials(CArchive & ar)
{
	CString line;
	int res;

	do
	{
		res = ar.ReadString( line );
	} while ( line != "#0" && res );
}

void CArcaedDoc::load_specials(CArchive & ar)
{
	char type;
	int i, vnum;
	CString specfun;

	while ( true )
	{
		type = toupper( fread_letter( ar ) );
		if ( type == 'S' || type == 0 ) return;
		if ( type == '*' )
		{
			fread_eol( ar );
			continue;
		}

		switch ( type )
		{
		case 'M':
			vnum = fread_number( ar );
			specfun = fread_word( ar );
			if ( ( i = FindMob( vnum ) ) != -1 )
				m_mobs[i]->m_specfun = specfun;
			break;
		}
	}

}

void CArcaedDoc::load_objects( CArchive & ar )
{
	CObjData *obj;
	int vnum, i, j;
	CString type;
	char letter;
	CAffectData *affect;
	CExtraDescr *extra;
	CTrainData *train;

	if ( fread_letter( ar ) != '#' ) return;
	while ( true )
	{
		vnum = fread_number( ar );
		if ( !vnum ) return;

		obj = new CObjData();
		obj->m_vnum = vnum;
		obj->m_name = fread_string( ar );
		obj->m_short_descr = fread_string( ar );
		obj->m_description = fread_string( ar );
		obj->m_material = fread_string( ar );

		obj->m_item_type = 0;
		type = fread_word( ar );
		type.MakeLower();
		for ( i = 0; i < tables.m_objtypes.GetSize(); i++ )
		{
			if ( type == tables.m_objtypes[i]->m_text )
			{
				obj->m_item_type = tables.m_objtypes[i]->m_num;
				break;
			}
		}

		if ( i >= tables.m_objtypes.GetSize() )
		{
			char buf[1000];
			CString tit, temp;

			tit.LoadString( IDS_ERROR );
			temp.LoadString( IDS_NOOBJ );
			sprintf( buf, temp,	obj->m_name, obj->m_vnum, type );
			MessageBox( NULL, buf, tit, MB_ICONERROR );
			AfxThrowUserException();
			return;
		}

		obj->m_extra_flags = fread_flags( ar );
		obj->m_wear_flags = fread_flags( ar );

		for ( j = 0; j < 5; j++ )
		{

			switch( tables.m_objtypes[i]->m_value[j].m_type )
			{
			default: obj->m_value_num[j] = fread_number( ar ); break;
			case 'S': obj->m_value_str[j] = fread_string( ar ); break;
			case 'D':
			case 'N':
			case 'E':
			case 'F': obj->m_value_num[j] = fread_flags( ar ); break;
			case 'L': 
			case 'O':
			case 'W': obj->m_value_str[j] = fread_word( ar ); break;
			}
		}

		obj->m_level = fread_number( ar );
		obj->m_weight = fread_number( ar );
		obj->m_cost = fread_number( ar );
		obj->m_condition = fread_letter( ar );

		while ( true )
		{

			letter = fread_letter( ar );
			if ( letter == '#' ) break;

			switch( letter )
			{
			case 'A':
				affect = new CAffectData();
				affect->m_where = AFF_TO_OBJECT;
				affect->m_location = fread_number( ar );
				affect->m_modifier = fread_number( ar );
				affect->m_flags = 0;
				obj->m_affdata.Add( affect );
				break;
			case 'F':
				affect = new CAffectData();
				letter = fread_letter( ar );
				switch( letter )
				{
				case 'A': affect->m_where = AFF_TO_AFFECTS; break;
				case 'I': affect->m_where = AFF_TO_IMMUNE; break;
				case 'R': affect->m_where = AFF_TO_RESIST; break;
				case 'V': affect->m_where = AFF_TO_VULN; break;
				}
				affect->m_location = fread_number( ar );
				affect->m_modifier = fread_number( ar );
				affect->m_flags = fread_flags( ar );
				obj->m_affdata.Add( affect );
				break;
			case 'E':
				extra = new CExtraDescr();
				extra->m_keyword = fread_string( ar );
				extra->m_description = fread_string( ar );
				obj->m_extradescr.Add( extra );
				break;
			case 'T':
				train = new CTrainData();
				train->m_room = fread_number( ar );
				train->m_flags = fread_flags( ar );
				train->m_time = fread_number( ar );
				train->m_msg = fread_string( ar );
				train->m_msgpart = fread_string( ar );
				obj->m_traindata.Add( train );
				break;
			}

		}

		m_objs.Add( obj );
	}

}

void CArcaedDoc::load_mobs( CArchive & ar )
{
	CMobData *mob;
	int vnum, flags, num, nrace;
	char letter;
	CString word, string, word2;
	CSkillData *skill;
	CMobProg *mobprog;
	CSkillPrac *skpr;
	CMobFlags *mobflags;
	CString temp, tit;
	char buf[1000];

	if ( fread_letter( ar ) != '#' ) return;
	while ( true )
	{
		vnum = fread_number( ar );
		if ( !vnum ) return;

		mob = new CMobData();
		mob->m_vnum = vnum;

		mob->m_name = fread_string( ar );
		mob->m_short_descr = fread_string( ar );
		mob->m_long_descr = fread_string( ar );
		mob->m_description = fread_string( ar );
		mob->m_race = fread_string( ar );

		for ( nrace = 0; nrace < tables.m_mobflags.GetSize(); nrace++ )
			if ( tables.m_mobflags[nrace]->m_race == mob->m_race )
				break;

		if ( nrace >= tables.m_mobflags.GetSize() )
		{
			temp.LoadString( IDS_NORACE );
			tit.LoadString( IDS_WARNING );
			sprintf( buf, temp, mob->m_race, mob->m_name,
				mob->m_vnum );
			temp = buf;
			MessageBox( NULL, temp, tit, MB_ICONWARNING );
			mobflags = new CMobFlags();
			mobflags->m_race = mob->m_race;
			nrace = tables.m_mobflags.Add( mobflags );
		}

		mob->m_act_flags = fread_flags( ar ) 
			| tables.m_mobflags[nrace]->m_act;
		mob->m_affect_flags = fread_flags( ar )
			| tables.m_mobflags[nrace]->m_aff;

		mob->m_alignment = fread_number( ar );
		mob->m_group = fread_number( ar );
		mob->m_level = fread_number( ar );
		mob->m_hitroll = fread_number( ar );

		mob->m_hit_dice_number = fread_number( ar );
		mob->m_hit_dice_type = fread_number( ar );
		mob->m_hit_dice_bonus = fread_number( ar );

		mob->m_mana_dice_number = fread_number( ar );
		mob->m_mana_dice_type = fread_number( ar );
		mob->m_mana_dice_bonus = fread_number( ar );

		mob->m_damage_dice_number = fread_number( ar );
		mob->m_damage_dice_type = fread_number( ar );
		mob->m_damage_dice_bonus = fread_number( ar );

		mob->m_dam_type = fread_word( ar );

		mob->m_ac_pierce = fread_number( ar ) * 10;
		mob->m_ac_bash = fread_number( ar ) * 10;
		mob->m_ac_slash = fread_number( ar ) * 10;
		mob->m_ac_exotic = fread_number( ar ) * 10;

		mob->m_off_flags = fread_flags( ar )
			| tables.m_mobflags[nrace]->m_off;
		mob->m_imm_flags = fread_flags( ar )
			| tables.m_mobflags[nrace]->m_imm;
		mob->m_res_flags = fread_flags( ar )
			| tables.m_mobflags[nrace]->m_res;
		mob->m_vuln_flags = fread_flags( ar )
			| tables.m_mobflags[nrace]->m_vul;

		mob->m_start_pos = fread_word( ar );
		mob->m_default_pos = fread_word( ar );
		mob->m_sex = fread_word( ar );

		mob->m_wealth = fread_number( ar );

		mob->m_form = fread_flags( ar )
			| tables.m_mobflags[nrace]->m_for;
		mob->m_parts = fread_flags( ar )
			| tables.m_mobflags[nrace]->m_par;

		mob->m_size = fread_word( ar );
		mob->m_material = fread_word( ar );

		while ( true )
		{

			letter = fread_letter( ar );
			if ( letter == '#' ) break;

			switch( letter )
			{
			case 'F':
				word = fread_word( ar );
				flags = fread_flags( ar );
				word.MakeUpper();
				if ( word == "ACT" )
					REMOVE_BIT( mob->m_act_flags, flags );
				else if ( word == "AFF" )
					REMOVE_BIT( mob->m_affect_flags, flags );
				else if ( word == "OFF" )
					REMOVE_BIT( mob->m_off_flags, flags );
				else if ( word == "IMM" )
					REMOVE_BIT( mob->m_imm_flags, flags );
				else if ( word == "RES" )
					REMOVE_BIT( mob->m_res_flags, flags );
				else if ( word == "VUL" )
					REMOVE_BIT( mob->m_vuln_flags, flags );
				else if ( word == "FOR" )
					REMOVE_BIT( mob->m_form, flags );
				else if ( word == "PAR" )
					REMOVE_BIT( mob->m_parts, flags );
				break;
			case 'G':
				word = fread_word( ar );
				word.MakeUpper();
				if ( word == "CLAN" )
					mob->m_clan = fread_string( ar );
				else if ( word == "RANK" )
					mob->m_rank = fread_number( ar ) + 1;
				else if ( word == "MERCMSG" )
				{
					num = fread_number( ar );
					string = fread_string( ar );
					if ( num >= 0 && num < tables.m_mercmsg.GetSize() )
						mob->m_mercmsg[num] = string;
				}
				break;
			case 'S':
				skill = new CSkillData();
				skill->m_percent = fread_number( ar );
				skill->m_skill = fread_word( ar );
				mob->m_skills.Add( skill );
				break;
			case 'M':
				mobprog = new CMobProg();
				mobprog->m_type = fread_word( ar );
				mobprog->m_vnum = fread_number( ar );
				mobprog->m_trigphrase = fread_string( ar );
				mob->m_mobprog.Add( mobprog );
				break;
			case 'P':
				word2 = fread_word( ar );
				if ( word2 == "class" )
				{
					mob->m_class = fread_word( ar );
				}
				else if ( word2 == "skill" )
				{
					skpr = new CSkillPrac();
					skpr->m_skill = fread_word( ar );
					skpr->m_gold = fread_number( ar );
					skpr->m_mult = fread_number( ar );
					skpr->m_maxlevel = fread_number( ar );
					skpr->m_teach = fread_number( ar );
					mob->m_trskill.Add( skpr );
				}
			}

		}

		m_mobs.Add( mob );
	}

}

void CArcaedDoc::AdjustRoom( int rindex, int x, int y, int nivel, int dir, int size )
{
	int i, j, k, nind, move;
	int rx, ry, ex, ey;

	move = FALSE;
	for ( i = 0; i < m_rooms.GetSize(); i++ )
	{
		rx = m_rooms[i]->m_posx;
		ry = m_rooms[i]->m_posy;
		if ( m_rooms[i]->m_unlinked ) continue;
		if ( rx == x && ry == y
			&& m_rooms[i]->m_nivel == nivel )
			move = TRUE;
		for ( j = 0; j < 5; j++ )
		{
			if ( ( k = m_rooms[i]->m_exits[j].m_vnum  ) > 0 )
			{
				if ( ( k = FindRoom( k, m_rooms[i]->m_vnum ) ) == -1 ) 
					continue;
				if ( m_rooms[k]->m_unlinked ||
					m_rooms[k]->m_nivel != nivel )
					continue;
				ex = m_rooms[k]->m_posx;
				ey = m_rooms[k]->m_posy;
				if ( ( dir == 0 || dir == 2 ) &&
					ry == y && ey == y && 
					( ( rx < x && x < ex ) || ( rx > x && x > ex ) ) )
					move = TRUE;
				if ( ( dir == 1 || dir == 3 ) &&
					rx == x && ex == x && 
					( ( ry < y && y < ey ) || ( ry > y && y > ey ) ) )
					move = TRUE;
			}
		}
		if ( move ) break;
	}
	if ( move )
		MoveRooms( x, y, dir, nivel, size );

	m_rooms[rindex]->m_unlinked = false;
	m_rooms[rindex]->m_posx = x;
	m_rooms[rindex]->m_posy = y;
	m_rooms[rindex]->m_nivel = nivel;

	for ( i = 0; i < 6; i++ )
	{
		if ( m_rooms[rindex]->m_exits[i].m_vnum )
		{
			nind = FindRoom( m_rooms[rindex]->m_exits[i].m_vnum );
			if ( nind == -1 || !m_rooms[nind]->m_unlinked ) 
				continue;
			x = m_rooms[rindex]->m_posx;
			y = m_rooms[rindex]->m_posy;
			switch( i )
			{
			case 0:
				AdjustRoom( nind, x, y-(size*4), nivel, 0, size );
				break;
			case 1:
				AdjustRoom( nind, x+(size*4), y, nivel, 1, size );
				break;
			case 2:
				AdjustRoom( nind, x, y+(size*4), nivel, 2, size );
				break;
			case 3:
				AdjustRoom( nind, x-(size*4), y, nivel, 3, size );
				break;
			case 4:
				AdjustRoom( nind, x, y, nivel+1, 0, size );
				break;
			case 5:
				AdjustRoom( nind, x, y, nivel-1, 0, size );
				break;
			}
		}
	}
	
}

int CArcaedDoc::FindRoom(int vnum, int exclude)
{
	int i;

	for ( i = 0; i < m_rooms.GetSize(); i++ )
		if ( m_rooms[i]->m_vnum == vnum 
			&& i != exclude )
			return i;

	return -1;
}

int CArcaedDoc::FindObj(int vnum, int exclude)
{
	int i;

	for ( i = 0; i < m_objs.GetSize(); i++ )
		if ( m_objs[i]->m_vnum == vnum 
			&& i != exclude )
			return i;

	return -1;
}

int CArcaedDoc::FindMob(int vnum, int exclude)
{
	int i;

	for ( i = 0; i < m_mobs.GetSize(); i++ )
		if ( m_mobs[i]->m_vnum == vnum 
			&& i != exclude )
			return i;

	return -1;
}

int CArcaedDoc::FindMobProg(int vnum, int exclude)
{
	int i;

	for ( i = 0; i < m_mobprogs.GetSize(); i++ )
		if ( m_mobprogs[i]->m_vnum == vnum 
			&& i != exclude )
			return i;

	return -1;
}

void CArcaedDoc::AdjustMap( int size )
{
	int i, minx, miny;

	if ( m_rooms.GetSize() <= 0 ) return;

	for ( i = 0; i < m_rooms.GetSize(); i++ )
	{
		m_rooms[i]->m_unlinked = true;
		m_rooms[i]->m_posx = 0;
		m_rooms[i]->m_posy = 0;
		m_rooms[i]->m_nivel = 0;
	}

	AdjustRoom( 0, 0, 0, 0, -1, size );
	
	minx = miny = size * 3;
	for ( i = 0; i < m_rooms.GetSize(); i++ )
	{
		if ( !m_rooms[i]->m_unlinked )
		{
			if ( m_rooms[i]->m_posx < minx )
				minx = m_rooms[i]->m_posx;
			if ( m_rooms[i]->m_posy < miny )
				miny = m_rooms[i]->m_posy;
		}
	}

	if ( minx < size * 3 ) minx -= size * 3;
	if ( miny < size * 3 ) miny -= size * 3;

	m_map_minlevel = m_map_maxlevel = 0;
	for ( i = 0; i < m_rooms.GetSize(); i++ )
	{
		if ( !m_rooms[i]->m_unlinked )
		{
			m_rooms[i]->m_posx -= minx;
			m_rooms[i]->m_posy -= miny;
			if ( m_rooms[i]->m_nivel > m_map_maxlevel )
				m_map_maxlevel = m_rooms[i]->m_nivel;
			if ( m_rooms[i]->m_nivel < m_map_minlevel )
				m_map_minlevel = m_rooms[i]->m_nivel;
		}
	}

}

void CArcaedDoc::MoveRooms(int x, int y, int dir, int nivel, int size)
{
	int i;

	for ( i = 0; i < m_rooms.GetSize(); i++ )
	{
		if ( m_rooms[i]->m_unlinked
			|| m_rooms[i]->m_nivel != nivel ) continue;
		switch ( dir )
		{
		case 0:
			if ( m_rooms[i]->m_posy <= y ) 
				m_rooms[i]->m_posy -= size * 4;
			break;
		case 1:
			if ( m_rooms[i]->m_posx >= x ) 
				m_rooms[i]->m_posx += size * 4;
			break;
		case 2:
			if ( m_rooms[i]->m_posy >= y ) 
				m_rooms[i]->m_posy += size * 4;
			break;
		case 3:
			if ( m_rooms[i]->m_posx <= x ) 
				m_rooms[i]->m_posx -= size * 4;
			break;
		}
	}
}

int CArcaedDoc::EditRoom( CRoomData *room )
{
	CRoomEd dlg;
	int i;
	CExtraDescr *extrad;
	CResetData *reset;

	if ( room == NULL ) return IDCANCEL;

	dlg.m_pDoc = this;
	dlg.m_index = FindRoom( room->m_vnum );
	dlg.m_minvnum = m_minvnum;
	dlg.m_maxvnum = m_maxvnum;
	dlg.m_Vnum = room->m_vnum;
	dlg.m_Name = room->m_name;
	dlg.m_Description = room->m_description;
	dlg.m_ManaGain = room->m_mana_rate;
	dlg.m_HitGain = room->m_heal_rate;
	dlg.m_Owner = room->m_owner;
	dlg.m_Clan = room->m_clan;
	dlg.m_cursector = room->m_sector_type;
	dlg.m_roomflags = room->m_room_flags;

	for ( i = 0; i < 6; i++ )
		dlg.m_exits[i] = room->m_exits[i];

	for ( i = 0; i < room->m_extradescr.GetSize(); i++ )
	{
		extrad = new CExtraDescr();
		*extrad = *room->m_extradescr[i];
		dlg.m_extradescr.Add( extrad );
	}

	for ( i = 0; i < room->m_resets.GetSize(); i++ )
	{
		reset = new CResetData();
		*reset = *room->m_resets[i];
		dlg.m_resets.Add( reset );
	}

	if ( dlg.DoModal() == IDOK )
	{
		room->m_vnum = dlg.m_Vnum;
		room->m_name = dlg.m_Name;
		room->m_description = dlg.m_Description;
		room->m_mana_rate = dlg.m_ManaGain;
		room->m_heal_rate = dlg.m_HitGain;
		room->m_owner = dlg.m_Owner;
		room->m_clan = dlg.m_Clan;
		room->m_sector_type = dlg.m_cursector;
		room->m_room_flags = dlg.m_roomflags;

		for ( i = 0; i < 6; i++ )
			room->m_exits[i] = dlg.m_exits[i];

		room->m_extradescr.RemoveAll();
		for ( i = 0; i < dlg.m_extradescr.GetSize(); i++ )
		{
			extrad = new CExtraDescr();
			*extrad = *dlg.m_extradescr[i];
			room->m_extradescr.Add( extrad );
		}

		room->m_resets.RemoveAll();
		for ( i = 0; i < dlg.m_resets.GetSize(); i++ )
		{
			reset = new CResetData();
			*reset = *dlg.m_resets[i];
			room->m_resets.Add( reset );
		}

		return IDOK;
	}

	return IDCANCEL;
}

int CArcaedDoc::FindFreeRoomVnum()
{
	int i, vnum;

	vnum = m_minvnum;

	for ( i = 0; i < m_rooms.GetSize() && vnum <= m_maxvnum; i++ )
	{
		if ( m_rooms[i]->m_vnum == vnum )
		{
			vnum++;
			i = -1;
		}
	}

	if ( vnum > m_maxvnum ) vnum = -1;

	return vnum;
}

int CArcaedDoc::FindFreeObjVnum()
{
	int i, vnum;

	vnum = m_minvnum;

	for ( i = 0; i < m_objs.GetSize() && vnum <= m_maxvnum; i++ )
	{
		if ( m_objs[i]->m_vnum == vnum )
		{
			vnum++;
			i = -1;
		}
	}

	if ( vnum > m_maxvnum ) vnum = -1;

	return vnum;
}

int CArcaedDoc::FindFreeMobVnum()
{
	int i, vnum;

	vnum = m_minvnum;

	for ( i = 0; i < m_mobs.GetSize() && vnum <= m_maxvnum; i++ )
	{
		if ( m_mobs[i]->m_vnum == vnum )
		{
			vnum++;
			i = -1;
		}
	}

	if ( vnum > m_maxvnum ) vnum = -1;

	return vnum;
}

int CArcaedDoc::FindFreeMobProgVnum()
{
	int i, vnum;

	vnum = m_minvnum;

	for ( i = 0; i < m_mobprogs.GetSize() && vnum <= m_maxvnum; i++ )
	{
		if ( m_mobprogs[i]->m_vnum == vnum )
		{
			vnum++;
			i = -1;
		}
	}

	if ( vnum > m_maxvnum ) vnum = -1;

	return vnum;
}

int CArcaedDoc::EditObj( CObjData *obj )
{
	CObjEd dlg;
	int i;
	CExtraDescr *extrad;
	CAffectData *affect;
	CTrainData *train;

	if ( obj == NULL ) return IDCANCEL;

	for ( dlg.m_index = 0; dlg.m_index < m_objs.GetSize(); dlg.m_index++ )
		if ( m_objs[dlg.m_index] == obj ) break;
	if ( dlg.m_index >= m_objs.GetSize() )
		dlg.m_index = -1;
	dlg.m_doc = this;

	dlg.m_Vnum = obj->m_vnum;
	dlg.m_Name = obj->m_name;
	dlg.m_ShortDescr = obj->m_short_descr;
	dlg.m_Description = obj->m_description;
	dlg.m_Material = obj->m_material;
	dlg.m_item_type = obj->m_item_type;
	dlg.m_extra_flags = obj->m_extra_flags;
	dlg.m_wear_flags = obj->m_wear_flags;
	for ( i = 0; i < 5; i++ )
	{
		dlg.m_value_num[i] = obj->m_value_num[i];
		dlg.m_value_str[i] = obj->m_value_str[i];
	}
	dlg.m_Nivel = obj->m_level;
	dlg.m_Peso = obj->m_weight;
	dlg.m_Costo = obj->m_cost;
	dlg.m_Condicion = obj->m_condition;
	for ( i = 0; i < obj->m_extradescr.GetSize(); i++ )
	{
		extrad = new CExtraDescr();
		*extrad = *obj->m_extradescr[i];
		dlg.m_extradescr.Add( extrad );
	}
	for ( i = 0; i < obj->m_affdata.GetSize(); i++ )
	{
		affect = new CAffectData();
		*affect = *obj->m_affdata[i];
		dlg.m_affects.Add( affect );
	}
	for ( i = 0; i < obj->m_traindata.GetSize(); i++ )
	{
		train = new CTrainData();
		*train = *obj->m_traindata[i];
		dlg.m_traindata.Add( train );
	}

	if ( dlg.DoModal() == IDOK )
	{
		obj->m_vnum = dlg.m_Vnum;
		obj->m_name = dlg.m_Name;
		obj->m_short_descr = dlg.m_ShortDescr;
		obj->m_description = dlg.m_Description;
		obj->m_material = dlg.m_Material;
		obj->m_item_type = dlg.m_item_type;
		obj->m_extra_flags = dlg.m_extra_flags;
		obj->m_wear_flags = dlg.m_wear_flags;
		for ( i = 0; i < 5; i++ )
		{
			obj->m_value_num[i] = dlg.m_value_num[i];
			obj->m_value_str[i] = dlg.m_value_str[i];
		}
		obj->m_level= dlg.m_Nivel;
		obj->m_weight = dlg.m_Peso;
		obj->m_cost = dlg.m_Costo;
		obj->m_condition = dlg.m_Condicion;

		obj->m_extradescr.RemoveAll();
		for ( i = 0; i < dlg.m_extradescr.GetSize(); i++ )
		{
			extrad = new CExtraDescr();
			*extrad = *dlg.m_extradescr[i];
			obj->m_extradescr.Add( extrad );
		}

		obj->m_affdata.RemoveAll();
		for ( i = 0; i < dlg.m_affects.GetSize(); i++ )
		{
			affect = new CAffectData();
			*affect = *dlg.m_affects[i];
			obj->m_affdata.Add( affect );
		}

		obj->m_traindata.RemoveAll();
		for ( i = 0; i < dlg.m_traindata.GetSize(); i++ )
		{
			train = new CTrainData();
			*train = *dlg.m_traindata[i];
			obj->m_traindata.Add( train );
		}

		return IDOK;
	}

	return IDCANCEL;
}

int CArcaedDoc::EditMob( CMobData *mob )
{
	int i;
	CMobEd dlg;
	CMobProg *mobprog;
	CSkillData *skill;
	CSkillPrac *prskill;

	if ( mob == NULL ) return IDCANCEL;

	for ( dlg.m_index = 0; dlg.m_index < m_mobs.GetSize(); dlg.m_index++ )
		if ( m_mobs[dlg.m_index] == mob ) break;
	if ( dlg.m_index >= m_mobs.GetSize() )
		dlg.m_index = -1;
	dlg.m_doc = this;

	dlg.m_Vnum = mob->m_vnum;
	dlg.m_Name = mob->m_name;
	dlg.m_ShortDescr = mob->m_short_descr;
	dlg.m_LongDescr = mob->m_long_descr;
	dlg.m_Description = mob->m_description;
	dlg.m_selrace = mob->m_race;
	dlg.m_act_flags = mob->m_act_flags;
	dlg.m_aff_flags = mob->m_affect_flags;
	dlg.m_Alignment = mob->m_alignment;
	dlg.m_Group = mob->m_group;
	dlg.m_Level = mob->m_level;
	dlg.m_HitRoll = mob->m_hitroll;
	dlg.m_HitDNumber = mob->m_hit_dice_number;
	dlg.m_HitDType = mob->m_hit_dice_type;
	dlg.m_HitDBonus = mob->m_hit_dice_bonus;
	dlg.m_ManaDNumber = mob->m_mana_dice_number;
	dlg.m_ManaDType = mob->m_mana_dice_type;
	dlg.m_ManaDBonus = mob->m_mana_dice_bonus;
	dlg.m_DamDNumber = mob->m_damage_dice_number;
	dlg.m_DamDType = mob->m_damage_dice_type;
	dlg.m_DamDBonus = mob->m_damage_dice_bonus;
	dlg.m_seldamtype = mob->m_dam_type;
	dlg.m_AcPierce = mob->m_ac_pierce;
	dlg.m_AcBash = mob->m_ac_bash;
	dlg.m_AcSlash = mob->m_ac_slash;
	dlg.m_AcExotic = mob->m_ac_exotic;
	dlg.m_off_flags = mob->m_off_flags;
	dlg.m_imm_flags = mob->m_imm_flags;
	dlg.m_res_flags = mob->m_res_flags;
	dlg.m_vuln_flags = mob->m_vuln_flags;
	dlg.m_form_flags = mob->m_form;
	dlg.m_parts_flags = mob->m_parts;
	dlg.m_start_pos = mob->m_start_pos;
	dlg.m_default_pos = mob->m_default_pos;
	dlg.m_sex = mob->m_sex;
	dlg.m_Wealth = mob->m_wealth;
	dlg.m_size = mob->m_size;
	dlg.m_Material = mob->m_material;
	if ( mob->m_shopdata != NULL )
	{
		dlg.m_shopdata = new CShopData();
		*dlg.m_shopdata = *mob->m_shopdata;
	}
	dlg.m_SpecFun = mob->m_specfun;
	for ( i = 0; i < mob->m_mobprog.GetSize(); i++ )
	{
		mobprog = new CMobProg;
		*mobprog = *mob->m_mobprog[i];
		dlg.m_mobprog.Add( mobprog );
	}
	dlg.m_clan = mob->m_clan;
	dlg.m_rank = mob->m_rank;
	for ( i = 0; i < mob->m_mercmsg.GetSize(); i++ )
		dlg.m_mercmsg.Add( mob->m_mercmsg[i] );
	for ( i = 0; i < mob->m_skills.GetSize(); i++ )
	{
		skill = new CSkillData();
		*skill = *mob->m_skills[i];
		dlg.m_skills.Add( skill );
	}
	for ( i = 0; i < mob->m_trskill.GetSize(); i++ )
	{
		prskill = new CSkillPrac;
		*prskill = *mob->m_trskill[i];
		dlg.m_trskill.Add( prskill );
	}
	dlg.m_class = mob->m_class;

	if ( dlg.DoModal() == IDOK )
	{
		mob->m_vnum = dlg.m_Vnum;
		mob->m_name = dlg.m_Name;
		mob->m_short_descr = dlg.m_ShortDescr;
		mob->m_long_descr = dlg.m_LongDescr;
		mob->m_description = dlg.m_Description;
		mob->m_race = dlg.m_selrace;
		mob->m_act_flags = dlg.m_act_flags;
		mob->m_affect_flags = dlg.m_aff_flags;
		mob->m_alignment = dlg.m_Alignment;
		mob->m_group = dlg.m_Group;
		mob->m_level = dlg.m_Level;
		mob->m_hitroll = dlg.m_HitRoll;
		mob->m_hit_dice_number = dlg.m_HitDNumber;
		mob->m_hit_dice_type = dlg.m_HitDType;
		mob->m_hit_dice_bonus = dlg.m_HitDBonus;
		mob->m_mana_dice_number = dlg.m_ManaDNumber;
		mob->m_mana_dice_type = dlg.m_ManaDType;
		mob->m_mana_dice_bonus = dlg.m_ManaDBonus;
		mob->m_damage_dice_number = dlg.m_DamDNumber;
		mob->m_damage_dice_type = dlg.m_DamDType;
		mob->m_damage_dice_bonus = dlg.m_DamDBonus;
		mob->m_dam_type = dlg.m_seldamtype;
		mob->m_ac_pierce = dlg.m_AcPierce;
		mob->m_ac_bash = dlg.m_AcBash;
		mob->m_ac_slash = dlg.m_AcSlash;
		mob->m_ac_exotic = dlg.m_AcExotic;
		mob->m_off_flags = dlg.m_off_flags;
		mob->m_imm_flags = dlg.m_imm_flags;
		mob->m_res_flags = dlg.m_res_flags;
		mob->m_vuln_flags = dlg.m_vuln_flags;
		mob->m_form = dlg.m_form_flags;
		mob->m_parts = dlg.m_parts_flags;
		mob->m_start_pos = dlg.m_start_pos;
		mob->m_default_pos = dlg.m_default_pos;
		mob->m_sex = dlg.m_sex;
		mob->m_wealth = dlg.m_Wealth;
		mob->m_size = dlg.m_size;
		mob->m_material = dlg.m_Material;
		if ( mob->m_shopdata != NULL )
		{
			delete mob->m_shopdata;
			mob->m_shopdata = NULL;
		}
		if ( dlg.m_shopdata != NULL )
		{
			mob->m_shopdata = dlg.m_shopdata;
			dlg.m_shopdata = NULL;
		}
		mob->m_specfun = dlg.m_SpecFun;
		mob->m_mobprog.RemoveAll();
		for ( i = 0; i < dlg.m_mobprog.GetSize(); i++ )
		{
			mobprog = new CMobProg;
			*mobprog = *dlg.m_mobprog[i];
			mob->m_mobprog.Add( mobprog );
		}
		mob->m_clan = dlg.m_clan;
		mob->m_rank = dlg.m_rank;
		mob->m_mercmsg.RemoveAll();
		for ( i = 0; i < dlg.m_mercmsg.GetSize(); i++ )
			mob->m_mercmsg.Add( dlg.m_mercmsg[i] );
		mob->m_skills.RemoveAll();
		for ( i = 0; i < dlg.m_skills.GetSize(); i++ )
		{
			skill = new CSkillData();
			*skill = *dlg.m_skills[i];
			mob->m_skills.Add( skill );
		}
		mob->m_trskill.RemoveAll();
		for ( i = 0; i < dlg.m_trskill.GetSize(); i++ )
		{
			prskill = new CSkillPrac;
			*prskill = *dlg.m_trskill[i];
			mob->m_trskill.Add( prskill );
		}
		mob->m_class = dlg.m_class;

		return IDOK;
	}

	return IDCANCEL;
}

void CArcaedDoc::save_area(CArchive & ar)
{

	arprintf( ar, "#AREADATA\n" );
	arprintf( ar, "Name %s~\n",         fix_string( m_name ) );
	arprintf( ar, "Builders %s~\n",     fix_string( m_builders ) );
	arprintf( ar, "VNUMs %d %d\n",      m_minvnum, m_maxvnum );
	arprintf( ar, "Credits %s~\n",      fix_string( m_credits ) );
	arprintf( ar, "Security %d\n",      m_security );

	if ( tables.m_mudtype == MUD_ARCANUM )
	{
		arprintf( ar, "NivelMax %d\n",      m_nivelmax );
		arprintf( ar, "NivelMin %d\n",      m_nivelmin );

		for ( int j = 0; j < m_recu.GetSize(); j++ )
			if ( m_recu[j]->m_num )
				arprintf( ar, "Recurso %d %d\n", j, m_recu[j]->m_num );
	}

	arprintf( ar, "End\n\n\n\n" );

}

void CArcaedDoc::save_areaold( CArchive & ar )
{
	CString fname = GetPathName();
	if ( fname.ReverseFind( '\\' ) != -1 )
		fname = fname.Mid( fname.ReverseFind( '\\' ) + 1 );

	arprintf( ar, "#AREA\n" );
	arprintf( ar, "%s~\n", fname );
	arprintf( ar, "%s~\n", fix_string( m_name ) );
	arprintf( ar, "%s~\n", fix_string( m_credits ) );
	arprintf( ar, "%d %d\n\n", m_minvnum, m_maxvnum );
}

void CArcaedDoc::save_mobs(CArchive & ar)
{
	int i, j, nrace;
	char buf[100];
	long temp;

	arprintf( ar, "#MOBILES\n" );

	for ( i = 0; i < m_mobs.GetSize(); i++ )
	{

		arprintf( ar, "#%d\n", m_mobs[i]->m_vnum );
		arprintf( ar, "%s~\n", fix_string( m_mobs[i]->m_name ) );
		arprintf( ar, "%s~\n", fix_string( m_mobs[i]->m_short_descr ) ); 
		arprintf( ar, "%s~\n", fix_string( format_string( m_mobs[i]->m_long_descr ) ) );
		arprintf( ar, "%s~\n", fix_string( format_string( m_mobs[i]->m_description) ) );
		arprintf( ar, "%s~\n", m_mobs[i]->m_race );
		arprintf( ar, "%s ", fwrite_flag( m_mobs[i]->m_act_flags, buf ) );
		arprintf( ar, "%s ", fwrite_flag( m_mobs[i]->m_affect_flags, buf ) );
		arprintf( ar, "%d %d\n", m_mobs[i]->m_alignment, m_mobs[i]->m_group);
		arprintf( ar, "%d ", m_mobs[i]->m_level );
		arprintf( ar, "%d ", m_mobs[i]->m_hitroll );

		arprintf( ar, "%dd%d+%d ", m_mobs[i]->m_hit_dice_number,
			m_mobs[i]->m_hit_dice_type,
			m_mobs[i]->m_hit_dice_bonus );
		arprintf( ar, "%dd%d+%d ", m_mobs[i]->m_mana_dice_number,
			m_mobs[i]->m_mana_dice_type,
			m_mobs[i]->m_mana_dice_bonus );
		arprintf( ar, "%dd%d+%d ", m_mobs[i]->m_damage_dice_number,
			m_mobs[i]->m_damage_dice_type,
			m_mobs[i]->m_damage_dice_bonus );

		arprintf( ar, "%s\n", m_mobs[i]->m_dam_type );
		arprintf( ar, "%d %d %d %d\n",
			m_mobs[i]->m_ac_pierce / 10,
			m_mobs[i]->m_ac_bash   / 10,
			m_mobs[i]->m_ac_slash  / 10,
			m_mobs[i]->m_ac_exotic / 10 );

		arprintf( ar, "%s ", fwrite_flag( m_mobs[i]->m_off_flags,  buf ) );
		arprintf( ar, "%s ", fwrite_flag( m_mobs[i]->m_imm_flags,  buf ) );
		arprintf( ar, "%s ", fwrite_flag( m_mobs[i]->m_res_flags,  buf ) );
		arprintf( ar, "%s\n", fwrite_flag( m_mobs[i]->m_vuln_flags, buf ) );

		arprintf( ar, "%s %s %s %ld\n",
			m_mobs[i]->m_start_pos,
			m_mobs[i]->m_default_pos,
			m_mobs[i]->m_sex,
			m_mobs[i]->m_wealth );

		arprintf( ar, "%s ", fwrite_flag( m_mobs[i]->m_form,  buf ) );
		arprintf( ar, "%s ", fwrite_flag( m_mobs[i]->m_parts, buf ) );

		arprintf( ar, "%s ", m_mobs[i]->m_size );
		arprintf( ar, "%s\n", m_mobs[i]->m_material != "" ? m_mobs[i]->m_material : "unknown" );

		for ( nrace = 0; nrace < tables.m_mobflags.GetSize(); nrace++ )
			if ( tables.m_mobflags[nrace]->m_race == m_mobs[i]->m_race )
				break;
		ASSERT( nrace < tables.m_mobflags.GetSize() );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_act,m_mobs[i]->m_act_flags)))
			arprintf( ar, "F act %s\n", fwrite_flag(temp, buf) );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_aff,m_mobs[i]->m_affect_flags)))
			arprintf( ar, "F aff %s\n", fwrite_flag(temp, buf) );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_off,m_mobs[i]->m_off_flags)))
			arprintf( ar, "F off %s\n", fwrite_flag(temp, buf) );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_imm,m_mobs[i]->m_imm_flags)))
			arprintf( ar, "F imm %s\n", fwrite_flag(temp, buf) );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_res,m_mobs[i]->m_res_flags)))
			arprintf( ar, "F res %s\n", fwrite_flag(temp, buf) );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_vul,m_mobs[i]->m_vuln_flags)))
			arprintf( ar, "F vul %s\n", fwrite_flag(temp, buf) );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_for,m_mobs[i]->m_form)))
			arprintf( ar, "F for %s\n", fwrite_flag(temp, buf) );

		if ((temp = DIF(tables.m_mobflags[nrace]->m_par,m_mobs[i]->m_parts)))
			arprintf( ar, "F par %s\n", fwrite_flag(temp, buf) );

		if ( m_mobs[i]->m_clan != "" )
		{
			arprintf(ar, "G clan %s~\n", m_mobs[i]->m_clan );
			arprintf(ar, "G rank %d\n", m_mobs[i]->m_rank - 1 );
		}

		for ( j = 0; j < m_mobs[i]->m_mercmsg.GetSize(); j++ )
			if ( m_mobs[i]->m_mercmsg[j] != "" )
				arprintf(ar, "G mercmsg %d %s~\n", j, m_mobs[i]->m_mercmsg[j] );

		for ( j = 0; j < m_mobs[i]->m_skills.GetSize(); j++ )
			arprintf(ar, "S %d '%s'\n",
				m_mobs[i]->m_skills[j]->m_percent, 
				m_mobs[i]->m_skills[j]->m_skill );

		for ( j = 0; j < m_mobs[i]->m_mobprog.GetSize(); j++ )
			arprintf(ar, "M %s %d %s~\n",
				m_mobs[i]->m_mobprog[j]->m_type, 
				m_mobs[i]->m_mobprog[j]->m_vnum,
				m_mobs[i]->m_mobprog[j]->m_trigphrase);

		if ( m_mobs[i]->m_class != "" )
			arprintf( ar, "P class '%s'\n", m_mobs[i]->m_class );

		for ( j = 0; j < m_mobs[i]->m_trskill.GetSize(); j++ )
			arprintf( ar, "P skill '%s' %i %i %i %i\n",
				m_mobs[i]->m_trskill[j]->m_skill,
				m_mobs[i]->m_trskill[j]->m_gold,
				m_mobs[i]->m_trskill[j]->m_mult,
				m_mobs[i]->m_trskill[j]->m_maxlevel,
				m_mobs[i]->m_trskill[j]->m_teach );

	}

	arprintf( ar, "#0\n\n\n\n" );
}

void CArcaedDoc::save_mobprog(CArchive & ar)
{
	int i;

	arprintf( ar, "#MOBPROGS\n" );

	for ( i = 0; i < m_mobprogs.GetSize(); i++ )
	{
		arprintf( ar, "#%d\n", m_mobprogs[i]->m_vnum );
		arprintf( ar, "%s~\n", fix_string( m_mobprogs[i]->m_code ) );
	}

	arprintf( ar,"#0\n\n" );
}

void CArcaedDoc::save_objects(CArchive & ar)
{
	int i, j, objindex;
	char buf[200];

	arprintf( ar, "#OBJECTS\n" );

	for ( i = 0; i < m_objs.GetSize(); i++ )
	{

		for ( objindex = 0; objindex < tables.m_objtypes.GetSize(); objindex++ )
			if ( tables.m_objtypes[objindex]->m_num == m_objs[i]->m_item_type )
				break;
		if ( objindex >= tables.m_objtypes.GetSize() ) continue;

		arprintf( ar, "#%d\n",    m_objs[i]->m_vnum );
		arprintf( ar, "%s~\n",    fix_string( m_objs[i]->m_name ) );
		arprintf( ar, "%s~\n",    fix_string( m_objs[i]->m_short_descr ) );
		arprintf( ar, "%s~\n",    fix_string( m_objs[i]->m_description ) );
		arprintf( ar, "%s~\n",    fix_string( m_objs[i]->m_material ) );
		arprintf( ar, "%s ",      tables.m_objtypes[objindex]->m_text );
		arprintf( ar, "%s ",      fwrite_flag( m_objs[i]->m_extra_flags, buf ) );
		arprintf( ar, "%s\n",     fwrite_flag( m_objs[i]->m_wear_flags,  buf ) );

		for ( j = 0; j < 5; j++ )
		{
			switch( tables.m_objtypes[objindex]->m_value[j].m_type )
			{
			default: arprintf( ar, "%d ", m_objs[i]->m_value_num[j] ); break;


			case 'I':
			case 'M':
			case 'A':
			case 'B':
			case 'U':
				arprintf( ar, "%d ", m_objs[i]->m_value_num[j] ); 
				break;

			case 'S':
				arprintf( ar, "%s~ ", fix_string( format_string( m_objs[i]->m_value_str[j] ) ) ); 
				break;

			case 'N':
			case 'F':
			case 'D':
			case 'E':
				arprintf( ar, "%s ", fwrite_flag( m_objs[i]->m_value_num[j], buf ) ); 
				break;

			case 'W':
			case 'L':
			case 'O':
				arprintf( ar, "'%s' ", fix_string( m_objs[i]->m_value_str[j] ) ); 
				break;

			}
		}

		arprintf( ar, "\n%d ", m_objs[i]->m_level );
		arprintf( ar, "%d ", m_objs[i]->m_weight );
		arprintf( ar, "%d ", m_objs[i]->m_cost );
		arprintf( ar, "%s\n", m_objs[i]->m_condition );

		for ( j = 0; j < m_objs[i]->m_affdata.GetSize(); j++ )
		{

			if ( m_objs[i]->m_affdata[j]->m_where == AFF_TO_OBJECT || m_objs[i]->m_affdata[j]->m_flags == 0)
				arprintf( ar, "A\n%d %d\n",  m_objs[i]->m_affdata[j]->m_location, m_objs[i]->m_affdata[j]->m_modifier );
			else
			{
				arprintf( ar, "F\n" );

				switch( m_objs[i]->m_affdata[j]->m_where )
				{
				case AFF_TO_AFFECTS:
					arprintf( ar, "A " );
					break;
				case AFF_TO_IMMUNE:
					arprintf( ar, "I " );
					break;
				case AFF_TO_RESIST:
					arprintf( ar, "R " );
					break;
				case AFF_TO_VULN:
					arprintf( ar, "V " );
					break;
				}

				arprintf( ar, "%d %d %s\n", m_objs[i]->m_affdata[j]->m_location, 
					m_objs[i]->m_affdata[j]->m_modifier,
					fwrite_flag( m_objs[i]->m_affdata[j]->m_flags, buf ) );
			}

		}

		for ( j = 0; j < m_objs[i]->m_extradescr.GetSize(); j++ )
		{
			arprintf( ar, "E\n%s~\n%s~\n", fix_string( m_objs[i]->m_extradescr[j]->m_keyword ),
				fix_string( format_string( m_objs[i]->m_extradescr[j]->m_description ) ) );
		}

		for ( j = 0; j < m_objs[i]->m_traindata.GetSize(); j++ )
		{
			arprintf( ar, "T %d %s %d %s~ %s~\n",
				m_objs[i]->m_traindata[j]->m_room, 
				fwrite_flag( m_objs[i]->m_traindata[j]->m_flags, buf ), 
				m_objs[i]->m_traindata[j]->m_time,
				fix_string( m_objs[i]->m_traindata[j]->m_msg ),
				fix_string( m_objs[i]->m_traindata[j]->m_msgpart ) );
		}

	}

	arprintf( ar, "#0\n\n\n\n" );
}

void CArcaedDoc::save_rooms(CArchive & ar)
{
	int i, j, door, locks;
	char buf[100];

	arprintf( ar, "#ROOMS\n" );
	for ( i = 0; i < m_rooms.GetSize(); i++ )
	{
		arprintf( ar, "#%d\n", m_rooms[i]->m_vnum );
		arprintf( ar, "%s~\n", fix_string( m_rooms[i]->m_name ) );
		arprintf( ar, "%s~\n", fix_string( format_string( m_rooms[i]->m_description ) ) );
		arprintf( ar, "0 " );
		arprintf( ar, "%d ", m_rooms[i]->m_room_flags );
		arprintf( ar, "%d\n", m_rooms[i]->m_sector_type );

		for ( j = 0; j < m_rooms[i]->m_extradescr.GetSize(); j++ )
		{
			arprintf( ar, "E\n%s~\n%s~\n", 
				fix_string( m_rooms[i]->m_extradescr[j]->m_keyword ),
				fix_string( format_string( m_rooms[i]->m_extradescr[j]->m_description ) ) );
		}

		for ( door = 0; door < 6; door++ )
		{
			if ( m_rooms[i]->m_exits[door].m_vnum <= 0 ) continue;
			locks = 0;

			if ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_ISDOOR )
			&& ( !IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_PICKPROOF ) )
			&& ( !IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_NOPASS ) ) )
				locks = 1;
			if ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_ISDOOR )
			&& ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_PICKPROOF ) )
			&& ( !IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_NOPASS ) ) )
				locks = 2;
			if ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_ISDOOR )
			&& ( !IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_PICKPROOF ) )
			&& ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_NOPASS ) ) )
				locks = 3;
			if ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_ISDOOR )
			&& ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_PICKPROOF ) )
			&& ( IS_SET( m_rooms[i]->m_exits[door].m_flags, EX_NOPASS ) ) )
				locks = 4;

			arprintf( ar, "D%d\n", door );
			arprintf( ar, "%s~\n", fix_string( format_string( m_rooms[i]->m_exits[door].m_description ) ) );
			arprintf( ar, "%s~\n", fix_string( m_rooms[i]->m_exits[door].m_keyword ) );
			arprintf( ar, "%d %d %d\n", locks,
				m_rooms[i]->m_exits[door].m_key,
				m_rooms[i]->m_exits[door].m_vnum );

			if ( m_rooms[i]->m_exits[door].m_flags 
				&& tables.m_mudtype == MUD_ARCANUM )
				arprintf( ar, "X%d %s\n", door,
				fwrite_flag( m_rooms[i]->m_exits[door].m_flags, buf ) );

		}

		if (m_rooms[i]->m_mana_rate != 100 || m_rooms[i]->m_heal_rate != 100)
			arprintf ( ar, "M %d H %d\n", m_rooms[i]->m_mana_rate,
				m_rooms[i]->m_heal_rate);

		if ( m_rooms[i]->m_clan != "" )
			arprintf ( ar, "C %s~\n" , m_rooms[i]->m_clan );

		if ( m_rooms[i]->m_owner != "" )
			arprintf ( ar, "O %s~\n" , m_rooms[i]->m_owner );

		arprintf( ar, "S\n" );

	}
	arprintf( ar, "#0\n\n\n\n" );
}

void CArcaedDoc::save_shops(CArchive & ar)
{
	int i, j;

	arprintf( ar, "#SHOPS\n" );

	for ( i = 0; i < m_mobs.GetSize(); i++ )
	{
		if ( m_mobs[i]->m_shopdata == NULL ) continue;

		arprintf( ar, "%d ", m_mobs[i]->m_vnum );
		for ( j = 0; j < 5; j++ )
			arprintf( ar, "%d ", m_mobs[i]->m_shopdata->m_trade[j] );
		arprintf( ar, "%d %d ", 
			m_mobs[i]->m_shopdata->m_percent_buy, 
			m_mobs[i]->m_shopdata->m_percent_sell );
		arprintf( ar, "%d %d\n", 
			m_mobs[i]->m_shopdata->m_open_hour, 
			m_mobs[i]->m_shopdata->m_close_hour );
	}

	arprintf( ar, "0\n\n\n\n" );
}

void CArcaedDoc::save_resets(CArchive & ar)
{
	int i, j, num;

	arprintf( ar, "#RESETS\n" );

	for ( i = 0; i < m_resets.GetSize(); i++ )
	{
		switch ( m_resets[i]->m_type )
		{
		case 'M': num = 4; break;
		case 'O': num = 3; break;
		case 'P': num = 4; break;
		case 'G': num = 2; break;
		case 'E': num = 3; break;
		case 'D': num = 3; break;
		case 'R': num = 2; break;
		default: num = 0; break;
		}

		if ( num )
		{
			arprintf( ar, "%c 0", m_resets[i]->m_type );
			for ( j = 0; j < num; j++ )
				arprintf( ar, " %d", m_resets[i]->m_num[j] );
			arprintf( ar, "\n" );
		}
	}

	arprintf( ar, "S\n\n\n\n" );
}

void CArcaedDoc::save_specials(CArchive & ar)
{
	int i;

	arprintf( ar, "#SPECIALS\n" );

	for ( i = 0; i < m_mobs.GetSize(); i++ )
		if ( m_mobs[i]->m_specfun != "" )
			arprintf( ar, "M %d %s\n", m_mobs[i]->m_vnum,
			m_mobs[i]->m_specfun );

	arprintf( ar, "S\n\n\n\n" );
}

void CArcaedDoc::UpdateRoomResets()
{
	int i, vnum, j;
	CResetData *reset;

	for ( i = 0; i < m_rooms.GetSize(); i++ )
		m_rooms[i]->m_resets.RemoveAll();

	vnum = -1;
	for ( i = 0; i < m_resets.GetSize(); i++ )
	{
		switch ( m_resets[i]->m_type )
		{
		case 'M':
		case 'O':
			vnum = m_resets[i]->m_num[2]; break;
		case 'P':
		case 'G':
		case 'E':
		default:
			break;
		case 'D':
		case 'R':
			vnum = m_resets[i]->m_num[0]; break;
		}
		if ( vnum != -1 )
		{
			j = FindRoom( vnum );
			if ( j != -1 )
			{
				reset = new CResetData();
				*reset = *m_resets[i];
				m_rooms[j]->m_resets.Add( reset );
			}
		}
	}
}

void CArcaedDoc::MakeResetList()
{
	int i, j;
	CResetData *reset;

	m_resets.RemoveAll();
	for ( i = 0; i < m_rooms.GetSize(); i++ )
	{
		for ( j = 0; j < m_rooms[i]->m_resets.GetSize(); j++ )
		{
			reset = new CResetData();
			*reset = *m_rooms[i]->m_resets[j];
			switch ( reset->m_type )
			{
			case 'M':
			case 'O':
				reset->m_num[2] = m_rooms[i]->m_vnum; break;
			case 'P':
			case 'G':
			case 'E':
			default:
				break;
			case 'D':
			case 'R':
				reset->m_num[0] = m_rooms[i]->m_vnum; break;
			}
			m_resets.Add( reset );
		}
	}
}