areabuilder/
areabuilder/creatures/
areabuilder/css/dark-hive/
areabuilder/objects/
areabuilder/rooms/
/* settings */
var defaults = {};
defaults['map_width'] =  30;
defaults['map_height'] = 30;

var material = [
"undefined","other","food","cloth","plant","wood","stone","granite","iron","steel","mithril",
"titanium","copper","bronze","silver","gold","diamond","ice","glass","paper","leather",
"ivory","ebony","flesh","skin","bone","water","crystal","earth","light"
];

var weapon_type = [ "undefined","shortsword","broadsword","longsword","handaxe","battleaxe","quarterstaff","polearm","mace","warhammer","morning star","club","dagger","whip","two-handed","bow","spear" ];
var apply_type = [ "none","str","dex","int","wis","con","cha","","","age","","","maxmana","maxhit","maxmove","","","armor","hitroll","damroll","save para","save rod","save petri","save breath","save spell" ];

var mob_progs = [ "act_prog", "speech_prog", "rand_prog", "fight_prog", "death_prog", "hitprcnt_prog", "entry_prog", "greet_prog", "all_greet_prog", "bribe_prog", "shout_prog", "tell_prog", "time_prog" ];

var obj_positions = [ 	{a:-1,b:'carried'},{a:0,b:'light'},{a:1,b:'finger 1'},{a:2,b:'finger 2'},{a:3,b:'neck 1'},{a:4,b:'neck 2'},{a:5,b:'body'},{a:6,b:'head'},{a:7,b:'legs'},
						{a:8,b:'feet'},{a:9,b:'hands'},{a:10,b:'arms'},{a:11,b:'shield'},{a:12,b:'about'},{a:13,b:'waist'},{a:14,b:'wrist 1'},{a:15,b:'wrist 2'},{a:16,b:'wield'},
						{a:17,b:'held'},{a:18,b:'face'},{a:19,b:'ear 1'},{a:20,b:'ear 2'},{a:21,b:'eyes'},{a:22,b:'ankle 1'},{a:23,b:'ankle 2'},{a:24,b:'wield 2'}];

var obj_liquids = [ 	{a:0,b:'water'},{a:1,b:'beer'},{a:2,b:'wine'},{a:3,b:'ale'},{a:4,b:'dark ale'},{a:5,b:'whisky'},{a:6,b:'lemonade'},{a:7,b:'firebreather'},
						{a:8,b:'moonshine'},{a:9,b:'slime'},{a:10,b:'milk'},{a:11,b:'tea'},{a:12,b:'coffee'},{a:13,b:'blood'},{a:14,b:'salt water'},{a:15,b:'fresh water'},{a:16,b:'coke'}];

var objects = [];
var dbr = {};

//array index of the currently selected zone, room, mob, object, shop
var Z, R, M, O, S;

//data hashes
var r = {}, m = {}, o = {}, s = {}, z = {};

var spells = [];

//icons
var mob_images = {};
var mob_index = [];									 
var room_images = {};
var room_index = [];				 
var obj_images = {};
var obj_index = [];

//the room grid
var grid = [];
var exits = [];
var dirs = [ 'north', 'east', 'south', 'west', 'up', 'down' ];
var rev_dir = [2, 3, 0, 1, 5, 4];
var north = 0;
var east = 	1;
var south = 2;
var west =	3;
var up =	4;
var down =	5;
var dir = { north: 0, east: 1, south: 2, west: 3, up: 4, down: 5};

$(document).ready(function(){ initUI() });

function initUI() {

	if (document.cookie.has('u=')) 
		$.get('login.php', function(data) { loginResponse(data) });
	else
		setTimeout("loginPrompt('Bedlam Areabuilder Login')", 700);
	
	$('#data').tabs({ 
		show: function(event, ui) { 
			if (ui.index == 0) { $('#map-wrapper').show(); $('#obj-wrapper').hide(); $('#mob-wrapper').hide(); }
			if (ui.index == 1) { $('#map-wrapper').hide(); $('#obj-wrapper').hide(); $('#mob-wrapper').show(); }
			if (ui.index == 2) { $('#map-wrapper').hide(); $('#obj-wrapper').show(); $('#mob-wrapper').hide(); }
		} 
	});
	
	$('.multiselect').multiselect({
		header: false,
		noneSelectedText: 'select',
		minWidth: 100
	});
	$('.multiselect').multiselect('uncheckAll');
	
	for (var i = 0; i < material.length; i++)
		if (material[i]) $('#obj-material').append('<option value="'+i+'">'+material[i]+'</option>');	
	
	$('.dropdown').selectmenu({style: 'dropdown', transferClasses: 'true'});
	$('.ui-sync').button({ icons: { primary: "ui-icon-refresh" }});
	$('.ui-publish').button({ icons: { primary: "ui-icon-arrowthick-1-n" }});
	$('.ui-save').button({ icons: { primary: "ui-icon-disk" }});
	$('.ui-revert').button({ icons: { primary: "ui-icon-arrowreturnthick-1-w" }});
	$('.ui-idea').button({ icons: { primary: "ui-icon-lightbulb" }});
	$('.ui-logout').button({ icons: { primary: "ui-icon-power" }});
	
	$('.cell').live('mousedown', function(e){ roomInit(e) } );
	$('.rcell').live('mousedown', function(e){ roomClick(e) } );
	$('.rcell').live('dblclick', function(e){ roomDoubleClick(e) } );
	
	$('.micon').live('mousedown', function(){ mobLoad($(this).attr('id').split('-')[1]) } );
	$('.oicon').live('mousedown', function(){ objLoad($(this).attr('id').split('-')[1]) } );
	
	$('.mcell').live('mousedown', function(e){ mobInit(e) } );
	$('.ocell').live('mousedown', function(e){ objInit(e) } );
	
	$('.max').live('change', function(){
		for (var i in z.reset)
			if (z.reset[i].LNUM == $(this).attr('lnum'))
				z.reset[i].Arg2 = $(this).val();
	});
	
	$('#command-type').live('change', function(){
		var v = $('.ui-dialog-content #command-type').val();
		if (v == 'M') {
			$('.ui-dialog-content #arg1-wrapper').html(buildMobSelect());
			$('.ui-dialog-content #select-mob').selectmenu({style: 'dropdown', transferClasses: 'true'});
			$('.ui-dialog-content #arg2-wrapper').html('Max:&nbsp;<input class="zreset max" id="arg2" value="1">');
			$('.ui-dialog-content #arg3-wrapper').hide();
		}
		if (v == 'O') {
			$('.ui-dialog-content #arg1-wrapper').html(buildObjSelect());
			$('.ui-dialog-content #select-obj').selectmenu({style: 'dropdown', transferClasses: 'true'});
			$('.ui-dialog-content #arg2-wrapper').html('Max:&nbsp;<input class="zreset max" id="arg2" value="1">');
			$('.ui-dialog-content #arg3-wrapper').hide();
		}
		if (v == 'P') {
			$('.ui-dialog-content #arg1-wrapper').html(buildObjSelect());
			$('.ui-dialog-content #arg2-wrapper').html('max:&nbsp;<input class="zreset max" id="arg2" value="1"> inside ');
			$('.ui-dialog-content #arg3-wrapper').html(buildObjSelect(r.data[R].VNUM));
			$('.ui-dialog-content .select-obj').selectmenu({style: 'dropdown', transferClasses: 'true'});
			$('.ui-dialog-content #arg3-wrapper').show();
		}
	});
	
	$('.ui-reset-load').live('mousedown', function() {
		zoneResetDelete($(this).attr('lnum'));
		roomLoad($(this).attr('vnum'));
	});
	$('.ui-reset-add').live('mousedown', function(){ showLoadMenu() } );
	
	$('#room-name').change(function() { r.data[R].Name = $(this).val() });
	$('#room-description').change(function() { r.data[R].Description = $(this).val().format() });
	
	$('#room-sector').change(function() { r.data[R].SectorType = $(this).selectmenu('value') });
	$("#room-flags").bind('multiselectclick', function() { r.data[R].RoomFlags = scanToInt('#room-flags') });
	
	$(".delete-exit").click(function() {
		var from = $('#room-id').val();
		var d = $(this).attr('id').split('-')[1];
		var to = $('#exit-'+d+'-toroom').val();
		if (!from || !to) return;
			for (var i = 0; i < r.exits.length; i++)
				if (r.exits[i].VNUM == from && r.exits[i].ToRoom == to && r.exits[i].NUM == dir[d]) {
					r.exits.splice(i, 1);
						$('#exit-'+d+'-toroom').val('');
						$('#exit-'+d+'-info').multiselect('uncheckAll');
						$('#exit-'+d+'-name').val('');
						$('#exit-'+d+'-key').val('');
					gridRefreshLinks();
					roomLoad(from);
				}
	});
	
	$(".link-exit").click(function() {
			var from = $('#room-id').val().toInt();
			var d = $(this).attr('id').split('-')[1];
			roomLink(from, dir[d], 0, true); //attempt with no reverse linking
			gridRefreshLinks();
			roomLoad(from);
	});
	
	for (var e = 0; e < 6; e++) {
		//Exit flags selector auto-escalates checkboxes
		$('#exit-'+dirs[e]+'-info').multiselect("widget").find(":checkbox").click(function() {
			if (this.checked)
				for (var i = 0; i < this.value.toInt(); i++)
					id(this.id.replace(this.value, i)).checked = true;
			else for (var i = this.value.toInt(); i < 4; i++)
					id(this.id.replace(this.value, i)).checked = false;
		});
	
		$('#exit-'+dirs[e]+'-info').bind("multiselectclick", function() {
			var inum = r.data[R].VNUM+'.'+dir[this.id.split('-')[1]];
				for (var i in r.exits)
					if (r.exits[i].INUM==inum)
						r.exits[i].ExitInfo = scanToInt('#'+$(this).attr('id'));
		});
		
		$('#exit-'+dirs[e]+'-name').change(function() {
		  var id = this.id.split('-')[1];
			if (!$('#exit-'+id+'-toroom').val()) return;
			if (!$('#exit-'+id+'-info').multiselect('getChecked')) return;
				for (var i in r.exits)
					if (r.exits[i].INUM==r.data[R].VNUM+'.'+dir[id])
						r.exits[i].Keyword = $(this).val();
		});
		
		$('#exit-'+dirs[e]+'-key').change(function() {
		  var id = this.id.split('-')[1];
			if (!$('#exit-'+id+'-toroom').val()) return;
			if (!$('#exit-'+id+'-info').multiselect('getChecked')) return;
				for (var i in r.exits)
					if (r.exits[i].INUM==r.data[R].VNUM+'.'+dir[id])
						r.exits[i].KeyNumber = $(this).val();
		});
	}
	
	$('#mob-name').change(function() { m.data[M].Name = $(this).val() });
	$('#mob-keywords').change(function() { m.data[M].Keywords = $(this).val() });
	$('#mob-level').change(function() { m.data[M].Level = $(this).val() });
	$('#mob-health').change(function() { m.points[M].BaseHit = $(this).val() });
	$('#mob-armor').change(function() { m.points[M].Armor = $(this).val() });
	$('#mob-hitroll').slider({
		value: 0,
		min: 0,
		max: 40,
		stop: function() { m.points[M].Hitroll = (20 - $(this).slider('option', 'value')).toString() }
	});
	
	$('#mob-exp').change(function() { m.points[M].Exp = $(this).val() });
	$('#mob-gold').change(function() { m.points[M].Gold = $(this).val() });
	$('#mob-align').change(function() { m.special_data[M].Align = $(this).val() });
	
	$('#mob-short').change(function() { m.data[M].Descr = $(this).val(); loadMobGrid() });
	$('#mob-long').change(function() { m.data[M].LongDescr = $(this).val().format() });
	
	$('#mob-flags').bind('multiselectclick', function() { m.special_data[M].MobFlags = scanToInt('#mob-flags') });
	$("#mob-affects").bind('multiselectclick', function() { m.special_data[M].AffectedBy = scanToInt('#mob-affects') });
	
	$('#mob-sex').change(function() { m.data[M].Sex = $(this).selectmenu('value') });
	$('#mob-class').change(function() { m.data[M].Class = $(this).selectmenu('value') });
	$('#mob-race').change(function() { m.special_data[M].Race = $(this).selectmenu('value') });
	
	$('.mob-attack').live('change', function() { mobAttackSet($(this).attr('inum'), $(this).attr('data'), $(this).val()) });
	$('.attack-type').live('change', function() { for (var i in m.attacks) if (m.attacks[i].INUM == $(this).attr('data')) { m.attacks[i].Type = $(this).val() } });
	$('.prog-type').live('change', function() { for (var i in m.progs) if (m.progs[i].INUM == $(this).attr('data')) m.progs[i].Type = $(this).val() });
	$('.prog-args').live('change', function() { for (var i in m.progs) if (m.progs[i].INUM == $(this).attr('data')) m.progs[i].ArgList = $(this).val() });
	$('.prog-commands').live('change', function() { for (var i in m.progs) if (m.progs[i].INUM == $(this).attr('data')) m.progs[i].Commands = $(this).val() });
	
	$('.mob-object').live('change', function() { mobObjectSet($(this).parent().attr('id').split('-')[2], $(this).attr('data'), $(this).val()) });
	$('.mob-object-position').live('change', function() { for (var i in m.objects) if (m.objects[i].INUM == $(this).attr('inum')) m.objects[i].Position = $(this).val() });
	$('.mob-object-number').live('change', function() { for (var i in m.objects) if (m.objects[i].INUM == $(this).attr('inum')) m.objects[i].ONUM = $(this).val() });
	
	$('.mob-product-select').live('change', function() { for (var i in s.products) if (s.products[i].INUM == $(this).attr('inum')) s.products[i].ONUM = $(this).val() });
	$('#mob-buy-type').live('change', function() { for (var i in s.buys) if (s.buys[i].INUM == $(this).attr('inum')) s.buys[i].OTYPE = $(this).val() });
	$('#mob-buy-keywords').live('change', function() { for (var i in s.buys) if (s.buys[i].INUM == $(this).attr('inum')) s.buys[i].Keywords = $(this).val() });
	
	$('.mob-buy-profit').live('change', function() { if ($(this).val() <= 100) { showDialog('Sell Profit Error', 'The value should be over 100%'); return } for (var i in s.data) if (s.data[i].SNUM == $(this).attr('snum')) s.data[i].BuyProfit = round(($(this).val()/100), 2) });
	$('.mob-sell-profit').live('change', function() { if ($(this).val() >= 100) { showDialog('Buy Profit Error', 'The value should be under 100%'); return } for (var i in s.data) if (s.data[i].SNUM == $(this).attr('snum')) s.data[i].SellProfit = round(($(this).val()/100), 2) });
	
	$('.attack-add').live('click', function() { mobAttackAdd(m.data[M].VNUM) } );
	$('.attack-delete').live('click', function() { mobAttackDelete($(this).attr('inum')) } );
	$('.mob-object-add').live('click', function() { mobObjectAdd(m.data[M].VNUM) } );
	$('.mob-object-delete').live('click', function() { mobObjectDelete($(this).attr('inum')) } );
	$('.prog-add').live('click', function() { mobProgAdd(m.data[M].VNUM) } );
	$('.prog-delete').live('click', function() { mobProgDelete($(this).attr('inum')) } );
	
	$('#obj-name').change(function() { o.data[O].ShortDesc = $(this).val(); loadObjGrid() });
	$('#obj-keywords').change(function() { o.data[O].Keywords = $(this).val() });
	$('#obj-short').change(function() { o.data[O].Descr = $(this).val() });
	$('#obj-type').change(function() { o.data[O].Type = $(this).selectmenu('value'); objTypeChange() });
	
	$('#obj-flags').bind('multiselectclick', function() { o.data[O].WearFlags = scanToInt('#obj-flags') });
	$('#obj-aff').bind('multiselectclick', function() { o.data[O].BitVector = scanToInt('#obj-aff') });
	$('#obj-extra').bind('multiselectclick', function() { o.data[O].ExtraFlags = scanToInt('#obj-extra') });
	
	$('#obj-v0').live('change', function() { o.data[O].Val0 = $(this).val() });
	$('#obj-v1').live('change', function() { o.data[O].Val1 = $(this).val() });
	$('#obj-v2').live('change', function() { o.data[O].Val2 = $(this).val() });
	$('#obj-v3').live('change', function() { o.data[O].Val3 = $(this).val() });
	$('#obj-material').live('change', function() { o.data[O].Val4 = $(this).selectmenu('value') });
	
	$('#obj-value').change(function() { o.data[O].Cost = $(this).val() });
	$('#obj-cost').change(function() { o.data[O].CostPerDay = $(this).val() });
	$('#obj-weight').change(function() { o.data[O].Weight = $(this).val() });
	
	$('.obj-input').live('change', function() { o.data[O][$(this).attr('data')] = $(this).val() });
	
	$('#obj-apply-button').click(function() {
			if ($(this).hasClass('collapsed')) {
				$('#obj-apply-form').show();
				$(this).removeClass('collapsed');
				$(this).removeClass('ui-icon-triangle-1-e');
				$(this).addClass('ui-icon-triangle-1-se');
			}
			else {
				$('#obj-apply-form').hide();
				$(this).addClass('collapsed');
				$(this).removeClass('ui-icon-triangle-1-se');
				$(this).addClass('ui-icon-triangle-1-e');
			}
	});
	
	$('.obj-desc-add').live('click', function() { objDescriptionAdd(o.data[O].VNUM) } );
	$('.obj-desc-delete').live('click', function() { objDescriptionDelete($(this).attr('inum')) } );
	$('.obj-desc').live('change', function() { o.extra[objFindExtra($(this).attr('inum'))][$(this).attr('data')] = $(this).val() });
	
	$('#area-name').change(function() { if (Z) z.data[Z].Name = $(this).val() });
	$('#area-lifespan').change(function() { if (Z) z.data[Z].Lifespan = $(this).val() });
	$('#area-flags').bind('multiselectclick', function() {if (Z) z.data[Z].Bits = scanToInt('#area-flags') });

	$('#map-view').change(function() { gridLoad(); $(document).scrollTop() });
	$("#data").tabs('select', '#data_area');
	
	$('.ui-tooltip').tooltip({
		position: 'bottom right',
		predelay: 400,
		effect: 'fade',
		tipClass: "ui-tooltip-custom ui-corner-all"
	});
}

function loadZones(d) {

	if (d.hasError()) return;
	
	z.data = eval('(' + d + ')');
	$('#select-area-container').html('<select id="select-area"><option value="-1">select area</option></select>');
	
	for (var i in z.data)
		if (z.data[i].CanEdit != '0' || z.data[i].CanAccess != '0')
			$('#select-area').append('<option value="' + i + '">' + z.data[i].Name + ((z.data[i].CanEdit == '0')?' [view]':' [edit]') + '</option>');

	$('#select-area').selectmenu({
		style: 'dropdown',
		width: 360,
		maxHeight: 700,
		change: function() { 
			Z = parseInt($(this).val());
			loadZone(1);
		}
	});
	
	globalProgress();
}

function loadZone(first) {
	globalProgress('Loading area: <b>' + z.data[Z].Name + '</b>');
	
	//dbr.flat = z.data[Z].Name.has('AB')?false:true;
		$('#map').html('<br><br><br><br>&nbsp;&nbsp;&nbsp;<img class="ui-corner-all" src="css/custom-theme/images/progress-bar.gif">');
		
		r = {};
		loadData('r_data', 'Data');
		loadData('r_exits', 'Exits');
		
		m = {};
		loadData('m_data', 'Data');
		loadData('m_special_data', 'SpecialData');
		loadData('m_points', 'Points');
		loadData('m_attacks', 'Attacks');
		loadData('m_objects', 'Objects');
		loadData('m_progs', 'Progs');
		loadData('m_abilities', 'Abilities');
		
		o = {};
		loadData('o_data', 'Data');
		loadData('o_extra', 'ExtraDescriptions');
		
		z.reset = [];
		loadData('z_reset', 'Reset');
		
		$('#area-id').val(z.data[Z].VNUM);
		$('#area-name').val(z.data[Z].Name);
		$('#area-lifespan').val(z.data[Z].Lifespan);
		$('#area-flags').multiselect('uncheckAll');
		z.data[Z].Bits.toFlag('#area-flags');
		
		$('.ui-revert').get(0).disabled=false;
		$('.ui-revert').removeClass('ui-state-disabled');
		$('#mob-level').get(0).disabled=false;
		$('#obj-short').get(0).disabled=false;
		
		loadData('s_data', 'Data');
		loadData('s_products', 'Products');
		loadData('s_buys', 'BuyTypes');
		
		if (z.data[Z].CanEdit == '0') {
			$('.ui-save').addClass('ui-state-disabled');
			$('.ui-save').get(0).disabled=true;
		}
		else {
			$('.ui-save').removeClass('ui-state-disabled');
			$('.ui-save').get(0).disabled=false;
		}
		
}

function loadData(what, from) {
	switch (what) {
		case 'z_data':
			$.get('controller.php?task=getareas', function(data) { loadZones(data) });
		break;
		case 'r_data':
			$.get('controller.php?task=getroom&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { globalProgress(); if (data.hasError()) return; 
			r.data = eval('(' + data + ')');
				if (z.data[Z].Published == '1') {
					$('.ui-sync').removeClass('ui-state-disabled');
					$('.ui-sync').get(0).disabled = false;
				}
				else {
					$('.ui-sync').addClass('ui-state-disabled');
					$('.ui-sync').get(0).disabled = true;
				}
			});
		break;
		case 'r_exits':
			$.get('controller.php?task=getroom&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) { r.exits = eval('(' + data + ')'); dbr.grid_start = r.exits[0].VNUM.toInt() } gridLoad() });
		break;
		case 'm_data':
			$.get('controller.php?task=getmob&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) m.data = eval('(' + data + ')'); loadMobGrid() });
		break;
		case 'm_special_data':
			$.get('controller.php?task=getmob&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) m.special_data = eval('(' + data + ')') });
		break;
		case 'm_points':
			$.get('controller.php?task=getmob&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) m.points = eval('(' + data + ')') });
		break;
		case 'm_attacks':
			$.get('controller.php?task=getmob&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) m.attacks = eval('(' + data + ')') });
		break;
		case 'm_objects':
			$.get('controller.php?task=getmob&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) m.objects = eval('(' + data + ')') });
		break;
		case 'm_abilities':
			$.get('controller.php?task=getmob&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) m.abilities = eval('(' + data + ')') });
		break;
		case 'm_progs':
			$.get('controller.php?task=getmob&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) m.progs = eval('(' + data + ')'); else m.progs = [] });
		break;
		case 'o_data':
			$.get('controller.php?task=getobj&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) o.data = eval('(' + data + ')'); loadObjGrid() });
		break;
		case 'o_extra':
			$.get('controller.php?task=getobj&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { if (data.hasError()) return; if (!data.has('Alert')) o.extra = eval('(' + data + ')') });
		break;
		case 'z_reset':
			$.get('controller.php?task=getzone&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { globalProgress(); if (data.hasError()) return; if (!data.has('Alert')) z.reset = eval('(' + data + ')') });
		break;
		case 's_data':
			$.get('controller.php?task=getshop&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { globalProgress(); if (data.hasError()) return; if (!data.has('Alert')) s.data = eval('(' + data + ')') });
		break;
		case 's_products':
			$.get('controller.php?task=getshop&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { globalProgress(); if (data.hasError()) return; if (!data.has('Alert')) s.products = eval('(' + data + ')') });
		break;
		case 's_buys':
			$.get('controller.php?task=getshop&id=' + z.data[Z].VNUM + '&t=' + from, function(data) { globalProgress(); if (data.hasError()) return; if (!data.has('Alert')) s.buys = eval('(' + data + ')') });
		break;
		case 'spells':
			$.get('controller.php?task=getspells', function(data) { if (data.hasError()) return; if (!data.has('Alert')) spells = eval('(' + data + ')') });
		break;
		case 'objects':
			$.get('controller.php?task=getobjects', function(data) { if (data.hasError()) return; if (!data.has('Alert')) objects = eval('(' + data + ')') });
		break;
	}
}

function gridLoad() {

	if (!r.data) { setTimeout('gridLoad()', 500); return }

	if (!r.exits || !r.exits.length) {
		roomInit(z.data[Z].VNUM*100);
	}
	
	var x, y, n, t, l = [];
	grid = [];
	grid[0] = [];
	
	if ($('#map-view').val() == 'layout') {
		grid[0].push(dbr.grid_start);
			for (var round = 0; round < 30; round++) {
			for (var i = 0; i < r.exits.length; i++) {
				x = 0, y = 0;
				n = r.exits[i].VNUM.toInt();
				t = r.exits[i].ToRoom.toInt();
				e = r.exits[i].NUM.toInt();
					if (n != dbr.grid_start && (t != dbr.grid_start && !getGridLocation(n).length && !getGridLocation(t).length)) continue;
					if (e > 3) continue;
					if (!r.exits[i].ToRoom.inZone(z.data[Z].VNUM.toInt())) continue;
					
					l = getGridLocation(n);
					if (l.length) { y = l[0]; x = l[1] }
					else {
						l = getGridLocation(n-1);
						if (l.length) { y = l[0]; x = l[1] }
						gridPlaceRoom(0, east, y, grid[y].length-1);
						gridPlaceRoom(n, south, y, grid[y].length-1);
						l = getGridLocation(n);
						if (l.length) { y = l[0]; x = l[1] }
					}
				
					if (!getGridLocation(t).length) 
						gridPlaceRoom(t, e, y, x);
					else { //to_room is already placed, move from_room relative to to_room
						grid[y][x] = 0;
						l = getGridLocation(t);
						y = l[0]; x = l[1];
						gridPlaceRoom(n, rev_dir[e], y, x);
					}
			}
			globalProgress('Analyzing area "'+z.data[Z].Name+'" - passes '+round+'/30');
		}
		gridZoomOut();
		if (grid.length == 3 || grid[0].length == 3) gridZoomOut();
		gridTrim();
		$('.freestyle').each(function() { $(this).get(0).disabled=true });
	}
	else {
		//list view	
		var i = 0;
		var n = z.data[Z].VNUM.toInt() * 100;
		var l = r.data[r.data.length-1].VNUM.slice(-2).toInt();
		for (var y = 0; y < parseInt(l/7)+2; y++) {
		  grid[y] = []; 
			for (var x = 0; x < 7; x++) {
				(roomFind(n+i) != -1)?grid[y].push(n+i):grid[y].push(0);
				i++;
			}
		}
		$('.freestyle').each(function() { $(this).get(0).disabled=false });
	}
	/*
	else if (!dbr.flat) {
	
			for (var i = 0; i < r.exits.length; i++) {

				x = 0, y = 0;
				n = r.exits[i].VNUM.toInt();
				t = r.exits[i].ToRoom.toInt();
				e = r.exits[i].NUM.toInt();
				z = z.data[Z].VNUM.toInt();
				
					if (e > 3) continue;
					if (!r.exits[i].ToRoom.inZone(z)) continue;
				
				//initial placement
					if (!grid[0].length) grid[0].push(n);
					else {
						l = getGridLocation(n);
						if (l.length) { y = l[0]; x = l[1] }
						else {
							l = getGridLocation(n-1);
							if (l.length) { y = l[0]; x = l[1] }
							gridPlaceRoom(0, east, y, grid[y].length-1);
							gridPlaceRoom(n, south, y, grid[y].length-1);
							l = getGridLocation(n);
							if (l.length) { y = l[0]; x = l[1] }
						}
					}
				
				if (!getGridLocation(t).length) 
					gridPlaceRoom(t, e, y, x);
				else { //to_room is placed, place from_room relative to to_room
					grid[y][x] = 0;
					l = getGridLocation(t);
					y = l[0]; x = l[1];
					gridPlaceRoom(n, rev_dir[e], y, x);
				}

				if (dbr.flat) break; //give up and show flat room grid
				
			} //end exits loop
			
		gridZoomOut();
		$('.freestyle').each(function() { $(this).get(0).disabled=true });
	}
	else {
		gridFlatten(); 
		$('.freestyle').each(function() { $(this).get(0).disabled=false });
	} */
	gridInit();
	gridRender();
}

function gridPrependRow() { var t = [];  for (i = 0; i < grid[0].length; i++) t.push(0); grid.unshift(t) }
function gridAppendRow() { var t = []; for (i = 0; i < grid[grid.length-1].length; i++) t.push(0); grid.push(t) }
function gridAppendColumn() { for (i = 0; i < grid.length; i++) grid[i].push(0) }
function gridPrependColumn() { for (i = 0; i < grid.length; i++) grid[i].unshift(0) }
function gridZoomOut() { gridPrependRow(); gridAppendRow(); gridPrependColumn(); gridAppendColumn() }
function gridTrim() {
	var trim_x = true;
	for (var y = 0; y < grid.length; y++) {
		for (var x = 0; x < grid[y].length; x++)
			if (x == grid[y].length-1 && grid[y][x-1]) trim_x = false;
	}
	if (trim_x) {
		for (var y = 0; y < grid.length; y++) grid[y].pop();
		gridTrim();
	}
}

function gridPlaceRoom(n, e, y, x) {
	if (!exists(grid[y]) || !exists(grid[y][x])) return;
	if (e == 0) { /* north */
		/* at top row? bump south */
		if (y == 0) gridPrependRow();
		else y--;
		if (!grid[y][x]) grid[y][x] = n;
	}
	else /* south */
	if (e == 2) {
		/* at bottom row? bump north */
		if (y == (grid.length-1)) gridAppendRow();
		y++;
		if (!grid[y][x]) grid[y][x] = n;
	}
	else /* east */
	if (e == 1) {
		/* at rightmost col? bump west */
		if (x == (grid[y].length-1)) gridAppendColumn();
		x++;
		if (!grid[y][x]) grid[y][x] = n;
	}
	else /* west */
	if (e == 3) {
		/* at leftmost col? bump east */
		if (x == 0) gridPrependColumn();
		else x--;
		if (!grid[y][x]) grid[y][x] = n;
	}
}

function getMaxWidth() {
	var w = 0;
	for (var y = 0; y < grid.length; y++)
		if (grid[y].length > w) w = grid[y].length;
	return w;
}

function getMaxHeight() { return grid.length; }

function getGridLocation(n) {
	for (y = 0; y < grid.length; y++)
		for (x = 0; x < grid[y].length; x++)
			if (grid[y][x] == n) return [y, x];
	return [];
}

function gridInit(wide) {

	globalProgress("Loading the map grid...");
	var v = z.data[Z].VNUM*100;
	var w = getMaxWidth();
	var h = getMaxHeight();

	if (w > 100) {
		$('#map-view').selectmenu('value', 1);
		return;
	}
	
	$('#map').html('');

	if (!wide) {
		$(".gridbox").width(400);
		$("#map").width(400);
	}
	
	var cell_size = parseInt(($(".gridbox").width() - (wide?160:60)) / w);
	if (cell_size < 15 && !wide) { 
		$(".gridbox").width(1060);
		$("#map").width(1060);
		gridInit(1);
		return;
	}
	
	if ($('#map-view').val() == 'list')
		cell_size = parseInt(($(".gridbox").width() - 20) / w);
		
	var x = 0, y = 0;
	
	for (var i = 0; i < (w * h); i++) {
		var myid = y + '-' + x;
		id("map").innerHTML += '<li class="cell ui-state-highlight context rContextClear" style="height: '+cell_size+'px; width: '+cell_size+'px" id="' + myid + '" vnum="' + v + '"></li>\n';
			$("#" + myid).width(cell_size);
			if ($('#map-view').val() == 'list')
				$("#" + myid).height(1.5*cell_size);
			else
				$("#" + myid).height(cell_size);
		if (((i+1)%w) == 0) {
			id("map").innerHTML += '<div class="c"></div>\n';
			y++; x=0;
		}
		else x++;
		v++;
	}

	//$("#map-wrapper").show();
	
	globalProgress();
}

function loadMobGrid() {

	if (!m.data || !m.data.length) 
		return mobInit(z.data[Z].VNUM*100);
	
	var w = 6;
	var cell_size = parseInt(($("#mob-icons").width() - 50) / w);
	
	$('#mob-icons').html('');
	
	for (var i = 0; i < 100; i++) {
		
		var myid = (z.data[Z].VNUM*100)+i;
		var mi = mobFind(myid);
		
		if (mi == -1)
			id("mob-icons").innerHTML += '<li class="mcell ui-state-highlight context mContextClear" style="height: '+cell_size+'px; width: '+cell_size+'px" id="mob-' + myid + '"></li>\n';
		else {
			id("mob-icons").innerHTML += '<li class="micon ui-widget-header context mContext" id="mob-' + myid + '" style="height: '+cell_size+'px; width: '+cell_size+'px"></li>\n';
			$("#mob-" + myid).html('<div class="vnum">'+myid.toString().slice(-2)+'</div><img class="mi" title="'+m.data[mi].Name+'" style="height: '+cell_size+'px; width: '+cell_size+'px" src="'+getMobPic(m.data[mi].Name)+'">');
		}
		
		if (((i+1)%w) == 0) 
			id("mob-icons").innerHTML += '<div class="c"></div>\n';
			
		if (i == (m.data[m.data.length-1].VNUM.toInt()-(z.data[Z].VNUM*100)) && i < (z.data[Z].VNUM*100)+99) {
			id("mob-icons").innerHTML += '<li class="mcell ui-state-highlight context mContextClear" style="height: '+cell_size+'px; width: '+cell_size+'px" id="mob-' + (myid+1) + '"></li>\n';
			break;
		}
	}
}

function loadObjGrid() {

	if (!o.data || !o.data.length) 
		return objInit(z.data[Z].VNUM*100);
	
	var w = 8;
	var cell_size = parseInt(($("#obj-icons").width() - 50) / w);
	
	$('#obj-icons').html('');
	
	for (var i = 0; i < 100; i++) {
		
		var myid = (z.data[Z].VNUM*100)+i;
		var mi = objFind(myid);
		
		if (mi == -1)
			id("obj-icons").innerHTML += '<li class="ocell ui-state-highlight context oContextClear" style="height: '+cell_size+'px; width: '+cell_size+'px" id="obj-' + myid + '"></li>\n';
		else {
			id("obj-icons").innerHTML += '<li class="oicon ui-widget-header context oContext" id="obj-' + myid + '" style="height: '+cell_size+'px; width: '+cell_size+'px"></li>\n';
			$("#obj-" + myid).html('<div class="vnum">'+myid.toString().slice(-2)+'</div><img class="mi" title="'+o.data[mi].ShortDesc+'" style="height: '+cell_size+'px; width: '+cell_size+'px" src="'+getObjPic(o.data[mi].ShortDesc)+'">');
		}
		
		if (((i+1)%w) == 0) 
			id("obj-icons").innerHTML += '<div class="c"></div>\n';
			
		if (i == (o.data[o.data.length-1].VNUM.toInt()-(z.data[Z].VNUM*100)) && i < (z.data[Z].VNUM*100)+99) {
			id("obj-icons").innerHTML += '<li class="ocell ui-state-highlight context mContextClear" style="height: '+cell_size+'px; width: '+cell_size+'px" id="obj-' + (myid+1) + '"></li>\n';
			break;
		}
	}
}

function gridRender() {

	var y, x, i, v, u, d, b, my, w;

	for (y = 0; y < grid.length; y++)
		for (x = 0; x < grid[y].length; x++)
			if (grid[y][x] > 0) {
				
				v = grid[y][x];
				i = roomFind(v);
				my = '#'+y+'-'+x;
				
				$(my).attr('class', 'rcell ui-widget-header context rContext');
				$(my).attr('title', v + ': ' + r.data[i].Name);
				$(my).attr('vnum',  v);
				
				if ($('#map-view').val() == 'list')
					$(my).html('<div class="vnum">'+v.toString().slice(-2)+'</div><img class="ri" vnum="'+v+'" title="'+v+': '+r.data[i].Name+'" style="height: 100%; width: 100%" src="'+getRoomPic(r.data[i].Name)+'">');
				else {
					w = '';
					u = getExitUp(v);
					d = getExitDown(v);
					if (u && d) w = 'updown'; else if (u) w = 'up'; else if (d) w = 'down';
					if (w)
						$(my).html('<div class="vnum">'+v.toString().slice(-2)+'</div><img class="ri" vnum="'+v+'" title="'+v+': '+r.data[i].Name+'" style="height: '+$(my).height()+'px; width: '+$(my).width()+'px" '+(w?' src="hub/stairs'+w+'.png"':'')+'">');
					else
						$(my).html('<div class="vnum">'+v.toString().slice(-2)+'</div>');
				}

			}
			
	if ($('#map-view').val() == 'layout') {
	
		b = '1px solid #eeeeee';
			$('.rcell').each(function() {
				var y = $(this).attr('id').split('-')[0].toInt();
				var x = $(this).attr('id').split('-')[1].toInt();
					if (y && grid[y-1][x] && !roomCheckLink(grid[y][x], grid[y-1][x]))
							$(this).css('border-top', b);
					if (x && grid[y][x-1] && !roomCheckLink(grid[y][x], grid[y][x-1]))
							$(this).css('border-left', b);
					if (y < (grid.length-1) && grid[y+1][x] && !roomCheckLink(grid[y][x], grid[y+1][x]))
							$(this).css('border-bottom', b);
					if (x < (grid[y].length-1) && grid[y][x+1] && !roomCheckLink(grid[y][x], grid[y][x+1]))
							$(this).css('border-right', b);
			});
		
		b = '1px solid #000000';
			$('.rcell').each(function() {
				var y = $(this).attr('id').split('-')[0].toInt();
				var x = $(this).attr('id').split('-')[1].toInt();
					if (y && grid[y-1][x] && roomCheckDoor(grid[y][x], grid[y-1][x]))
							$(this).css('border-top', b);
					if (x && grid[y][x-1] && roomCheckDoor(grid[y][x], grid[y][x-1]))
							$(this).css('border-left', b);
					if (y < (grid.length-1) && grid[y+1][x] && roomCheckDoor(grid[y][x], grid[y+1][x]))
							$(this).css('border-bottom', b);
					if (x < (grid[y].length-1) && grid[y][x+1] && roomCheckDoor(grid[y][x], grid[y][x+1]))
							$(this).css('border-right', b);
			});
	}
	
	//enable context menus
	contextReset();
}

function gridRefreshLinks() {
	gridInit();
	gridRender();
}

function contextReset() {

	$(".context").destroyContextMenu();
	
	$(".rContext").contextMenu(
		{ menu: 'rContext' },
		function(action, el, pos) {
			if (action == 'cut') { dbr.room_cut = $(el).attr('vnum'); dbr.room_copy = 0 }
			else if (action == 'copy') dbr.room_copy = $(el).attr('vnum');
			else if (action == 'paste') roomPaste(dbr.room_copy, $(el).attr('vnum'), el);
			else if (action == 'reset') roomReset($(el).attr('vnum'), el);
			else if (action == 'delete') roomDelete($(el).attr('vnum'));
			else if (action == 'up') roomDig(el, up);
			else if (action == 'down') roomDig(el, down);
			else if (action == 'load') showLoadMenu();
	});
	
	$(".rContextClear").contextMenu(
		{ menu: 'rContextClear' },
		function(action, el, pos) {
			if (action == 'paste') 
				roomMove(dbr.room_cut, el);
	});
	
	$(".mContext").contextMenu(
		{ menu: 'mContext' },
		function(action, el, pos) {
			if (action == 'cut') { dbr.mob_cut = $(el).attr('vnum'); dbr.mob_copy = 0 }
			else if (action == 'copy') dbr.mob_copy = $(el).attr('id').split('-')[1];
			else if (action == 'paste') mobPaste(el);
			else if (action == 'delete') { mobDelete($(el).attr('id').split('-')[1]); loadMobGrid() }
			else if (action == 'load') mobObjectAdd($(el).attr('id').split('-')[1]);
	});
	
	$(".mContextClear").contextMenu(
		{ menu: 'mContextClear' },
		function(action, el, pos) {
			if (action == 'move') 
				mobMove(el);
			else (action == 'clone') 
				mobInit(null, el);
	});
	
}

function contextBeforeShow(el) {
	
	if ($('#map-view').val() != 'layout') {
		$('#rContext .down').hide();
		$('#rContext .up').hide();
		return;
	}
	
	if ($(el).html().has('updown')) {
		$('#rContext .up-text').html('Go Up');
		$('#rContext .down-text').html('Go Down');
		$('#rContext .up').show();
		$('#rContext .down').show();
		return;
	}
	
	if ($(el).html().has('up')) {
		$('#rContext .up-text').html('Go Up');
		$('#rContext .down-text').html('Dig Down');
		$('#rContext .up').show();
		$('#rContext .down').show();
		return;
	}
	
	if ($(el).html().has('down')) {
		$('#rContext .up-text').html('Dig Up');
		$('#rContext .down-text').html('Go Down');
		$('#rContext .up').show();
		$('#rContext .down').show();
		return;
	}
	
		$('#rContext .up-text').html('Dig Up');
		$('#rContext .down-text').html('Dig Down');
		$('#rContext .up').show();
		$('#rContext .down').show();
}

function roomCheckLink(A, B) {
	for (var i = 0; i < r.exits.length; i++) {
		if (r.exits[i].VNUM != A) continue;
		if (r.exits[i].ToRoom == B) return true;
	}
	return false;
}
function roomCheckDoor(A, B) {
	for (var i = 0; i < r.exits.length; i++) {
		if (r.exits[i].VNUM != A) continue;
		if (r.exits[i].ToRoom == B && r.exits[i].ExitInfo != '0') return true;
	}
	return false;
}
function roomCheckPlacement(y, x) {
	if (grid.length == 1) return true;
	if (x && grid[y][x-1]) return true;
	if (y && grid[y-1][x]) return true;
	if (x < grid[y].length - 1 && grid[y][x+1]) return true;
	if (y < grid.length - 1 && grid[y+1][x]) return true;
	return false;
}
/* room grid interactions */

function roomClick(evt) {
	evt = evt?evt:window.event; 
	if (evt.which != 1) return false;
	var el = evt.target||evt.srcElement;
	//if (!$(el).hasClass('ui-state-active')) {
		roomLoad($(el).attr('vnum'));
		$('.rcell').removeClass('ui-state-active');
		if ($(el).is('img'))
			$(el).parent().addClass('ui-state-active'); 
		else $(el).addClass('ui-state-active');
	//}
}
function roomDoubleClick(evt) {
	evt = evt?evt:window.event;
	if (evt.which != 1) return false;
	var el = evt.target||evt.srcElement;
}
/* room saving & loading */
function roomInit(evt) {

	evt = evt?evt:window.event; 
	if (evt.which != 1) return false;
	var el = evt.target||evt.srcElement;
	
	var vnum;

	if ($('#map-view').val() == 'list')
	vnum = $(el).attr('vnum');
	else vnum = getFreeVnum(r.data);

	if (vnum == -1) { 
		showDialog('Room creation error', 'There are no more free unique room numbers in the current area. Delete some rooms first or request another area.'); 
		return false;
	}
	
	var y = el.id.split('-')[0].toInt();
	var x = el.id.split('-')[1].toInt();
	
	/*
	if (!dbr.flat && !roomCheckPlacement(y, x)) {
		showDialog('Room placement error', 'The areabuilder doesn\'t allow unlinked rooms. You can add spacial irregularities later using OLC.'); 
		return false;
	}*/
	
	grid[y][x] = vnum;
	$(el).attr('vnum', vnum);

	r.data.push({
		Zone: z.data[Z].VNUM,
		VNUM: vnum.toString(),
		Name: 'New room',
		Description: 'You are in an unfinished room.\r\n',
		RoomFlags: '0',
		SectorType: '0'
	});
	
	r.data = sortHash(r.data, 'VNUM');
	
	roomAutoLink(vnum, y, x);
	r.exits = sortHash(r.exits, 'INUM');	
	
	if ($('#map-view').val() != 'list')
	for (y = 0; y < grid.length; y++)
		for (x = 0; x < grid[y].length; x++) {
			if (!grid[y][x]) continue;
				if (!y) gridPrependRow();
				if (!x) gridPrependColumn();
				if (y == grid.length-1) gridAppendRow();
				if (x == grid[y].length-1) gridAppendColumn();
			gridInit(); 
		}
	
	gridRender();
	$('#'+y+'-'+x).trigger({ type: 'mousedown', which: 1 });
}

function roomLoad(vnum) {
	if ($("*:focus").html() != null) $("*:focus").get(0).blur();
	//$('#room-flags').multiselect('uncheckAll');
	
	$("#data").tabs('select', '#data_rooms');
	R = roomFind(vnum);
	
	$('#room-name').val(r.data[R].Name);
	$('#room-id').val(r.data[R].VNUM);
	
	r.data[R].RoomFlags.toFlag('#room-flags');
	
	$('#room-sector').selectmenu('value', r.data[R].SectorType);
	$('#room-description').val(r.data[R].Description.format());
	
	for (i = 0; i < dirs.length; i++) {
		$('#exit-'+dirs[i]+'-toroom').val('');
		$('#exit-'+dirs[i]+'-keyword').val('');
		$('#exit-'+dirs[i]+'-key').val('');
		$('#exit-'+dirs[i]+'-info').multiselect('uncheckAll');
	}
	
	$('.delete-exit').hide();
	$('.link-exit').hide();
		
	for (i in r.exits) {
		if (r.exits[i].VNUM != vnum) continue;
		if (r.exits[i].ToRoom == '-1') continue;
		var e = r.exits[i].NUM.toInt();
		$('#exit-'+dirs[e]+'-toroom').val(r.exits[i].ToRoom);
		$('#exit-'+dirs[e]+'-keyword').val(r.exits[i].Keyword);
		$('#exit-'+dirs[e]+'-key').val(r.exits[i].KeyNumber);
		r.exits[i].ExitInfo.toFlag('#exit-'+dirs[e]+'-info');
		//if (!dbr.flat) 
		$('#del-'+dirs[e]).show();
	}
	
	//if (!dbr.flat)
		for (i = 0; i < 6; i++) 
			if (!$('#del-'+dirs[i]).is(":visible"))
				$('#link-'+dirs[i]).show();
				
	$('#room-loads').html('');
	var html = '', l, obj_to = [];
		for (i in z.reset) {
			l = z.reset[i].LNUM;
			if (z.reset[i].Arg3 == vnum && z.reset[i].Command == 'M') {
				html += '<span class="left ui-icon ui-icon-circle-close ui-reset-load" lnum="'+l+'" vnum="'+vnum+'"></span>&nbsp;Mob: <a href="#" onclick="mobLoad('+m.data[mobFind(z.reset[i].Arg1)].VNUM+')">' + m.data[mobFind(z.reset[i].Arg1)].Name + '</a> max: <input class="zreset max" lnum="'+l+'" arg="Arg2" value="' + z.reset[i].Arg2 + '"><div class="sep"></div>';
			}
			else if (z.reset[i].Arg3 == vnum && z.reset[i].Command == 'O') {
				html += '<span class="left ui-icon ui-icon-circle-close ui-reset-load" lnum="'+l+'" vnum="'+vnum+'"></span>&nbsp;Obj: <a href="#" onclick="objLoad('+o.data[objFind(z.reset[i].Arg1)].VNUM+')">' + o.data[objFind(z.reset[i].Arg1)].ShortDesc + '</a> max: <input class="zreset max" lnum="'+l+'" arg="Arg2" value="' + z.reset[i].Arg2 + '"><div class="sep"></div>';
				obj_to.push(o.data[objFind(z.reset[i].Arg1)].VNUM);
			}
			else if (z.reset[i].Command == 'P' && $.inArray(z.reset[i].Arg3, obj_to) != -1) {
				html += '<span class="left ui-icon ui-icon-circle-close ui-reset-load" lnum="'+l+'" vnum="'+vnum+'"></span>&nbsp;Put: ' + o.data[objFind(z.reset[i].Arg1)].ShortDesc + ' max: <input class="zreset max" lnum="'+l+'" arg="Arg2" value="' + z.reset[i].Arg2 + '"> inside ' + o.data[objFind(z.reset[i].Arg3)].ShortDesc + '<div class="sep"></div>';
			}
			
		}
		$('#room-loads').html('<span class="left ui-icon ui-icon-circle-plus ui-reset-add"></span>&nbsp;<b>Loads:</b><br><br>' + html + '<div class="sep"></div>');
}

function roomLink(from, dir, to, no_rev) {
	if (!to) {
		var l = getGridLocation(from.toString());
		if (!l.length) return false;
		var y = l[0]; var x = l[1];
		switch (dir) {
			case 0:	if (!y || !grid[y-1][x]) 					return false; else to = grid[y-1][x]; break;
			case 1:	if (x == grid[y].length-1 || !grid[y][x+1]) return false; else to = grid[y][x+1]; break;
			case 2:	if (y == grid.length-1 || !grid[y+1][x]) 	return false; else to = grid[y+1][x]; break;
			case 3:	if (!x || !grid[y][x-1]) 					return false; else to = grid[y][x-1]; break;
			default :   return false; break;
		}
	}
	r.exits.push({
		VNUM: from.toString(),
		NUM: dir.toString(),
		Description: '',
		Keyword: '',
		ExitInfo: '0',
		KeyNumber: '0',
		ToRoom: to.toString(),
		INUM: from + '.' + dir
	});
	if (no_rev) return true;
	r.exits.push({
		VNUM: to.toString(),
		NUM: rev_dir[dir].toString(),
		Description: '',
		Keyword: '',
		ExitInfo: '0',
		KeyNumber: '0',
		ToRoom: from.toString(),
		INUM: to + '.' + rev_dir[dir]
	});
}

function roomPaste(from, to, el) {
	if (!from) {
		showDialog('Room paste error.', 'No room properties found in clipboard.');
		return false;
	}
	var vnum = to;
	from = roomFind(from);
	to = roomFind(to);
	r.data[to].Name = r.data[from].Name;
	r.data[to].Description = r.data[from].Description;
	r.data[to].RoomFlags = r.data[from].RoomFlags;
	r.data[to].SectorType = r.data[from].SectorType;
	roomLoad(vnum);
}

function roomMove(cut, el) {
	if (!cut) {
		showDialog('Room move error.', 'No \'cut\' room found in clipboard.');
		return false;
	}
	
	var y = $(el).attr('id').split('-')[0].toInt();
	var x = $(el).attr('id').split('-')[1].toInt();
	var l = getGridLocation(cut);
	
	grid[y][x] = cut;
	grid[l[0]][l[1]] = 0;
	
	roomDeleteExits(cut);
	roomAutoLink(cut, y, x);
	r.exits = sortHash(r.exits, 'INUM');
		
	if (!x) x = 1;
	if (!y) y = 1;	
	gridLoad();
	
	$('#'+y+'-'+x).trigger({ type: 'mousedown', which: 1 });
}

function roomReset(room, el) {
	var vnum = room;
	room = roomFind(room);
	r.data[room].Name = 'New Room';
	r.data[room].Description = 'You are in an unfinished room.';
	r.data[room].RoomFlags = '0';
	r.data[room].SectorType = '0';
	$(el).trigger({ type: 'mousedown', which: 1 });
}

function roomDig(el, dir) {
	var from = $(el).attr('vnum');
	var to = (dir==up)?getExitUp(from):getExitDown(from);
	
	if (!to) {
	
		to = getFreeVnum(r.data);
		if (to == -1) { 
			showDialog('Room creation error', 'There are no more free unique room numbers in the current area. Delete some rooms first or request a new area.'); 
			return false;
		}
			
		r.data.push({
			Zone: z.data[Z].VNUM,
			VNUM: to.toString(),
			Name: 'New room',
			Description: 'You are in an unfinished room.\r\n',
			RoomFlags: '0',
			SectorType: '0'
		});
		
		roomLink(from, dir, to);
		r.exits = sortHas(r.exits, 'INUM');
	}
	
	dbr.grid_start = to;
	gridLoad();	
}

function roomDelete(vnum) {
	r.data.splice(roomFind(vnum), 1);
	roomDeleteExits(vnum);
	gridLoad();
}

function roomDeleteExits(vnum) {
	for (var i = r.exits.length-1; i >=0; i--)
		if (r.exits[i].VNUM == vnum || r.exits[i].ToRoom == vnum)
			r.exits.splice(i, 1);
}

function roomAutoLink(vnum, y, x) {
	if ($('#map-view').val() == 'list') return;
	if (y && grid[y-1][x]) 
		roomLink(vnum, north, grid[y-1][x]);
	if (y < grid.length-1 && grid[y+1][x])
		roomLink(vnum, south, grid[y+1][x]);
	if (x && grid[y][x-1]) 	
		roomLink(vnum, west, grid[y][x-1]);
	if (x < grid[0].length-1 && grid[y][x+1]) 
		roomLink(vnum, east, grid[y][x+1]);
}

function mobLoad(vnum) {

	if ($("*:focus").html() != null) $("*:focus").get(0).blur();
	$("#data").tabs('select', '#data_mobs');
	
	$('.micon').removeClass('ui-state-active');
	$('#mob-'+vnum).addClass('ui-state-active');
	
	//$('#mob-flags').multiselect('uncheckAll');
	//$('#mob-affects').multiselect('uncheckAll');
	
	M = mobFind(vnum);
	
	$('#mob-name').val(m.data[M].Name);
	$('#mob-keywords').val(m.data[M].Keywords);
	$('#mob-level').val(m.data[M].Level);
	$('#mob-id').val(m.data[M].VNUM);
	
	m.special_data[M].MobFlags.toFlag('#mob-flags');
	m.special_data[M].AffectedBy.toFlag('#mob-affects');
	$('#mob-sex').selectmenu('value', m.data[M].Sex);
	$('#mob-class').selectmenu('value', m.data[M].Class);
	$('#mob-race').selectmenu('value', m.special_data[M].Race);
	
	$('#mob-short').val(m.data[M].Descr.stripBreaks());
	$('#mob-long').val(m.data[M].LongDescr.stripBreaks());

	$('#mob-health').val(m.points[M].BaseHit);
	$('#mob-armor').val(m.points[M].Armor);
	$('#mob-hitroll').slider('option', 'value', 20 - m.points[M].Hitroll.toInt());
	
	$('#mob-exp').val(m.points[M].Exp);
	$('#mob-gold').val(m.points[M].Gold);
	$('#mob-align').val(m.special_data[M].Align);
	mobAttacksLoad(vnum);
	mobObjectsLoad(vnum);
	mobProgsLoad(vnum);
	mobShopLoad(vnum);
}

function mobAttacksLoad(vnum) {
	$('#mob-attacks').html('<span class="left ui-icon ui-icon-circle-plus attack-add"></span>&nbsp;<b>Attacks:</b><br><br>');
	var n = 0;
	for (var i in m.attacks) {
		if (m.attacks[i].VNUM != vnum) continue;
			$('#mob-attacks').append('<div id="mob-attack-'+m.attacks[i].INUM+'"><span class="left">\
			<span class="left ui-icon ui-icon-circle-close attack-delete" inum="'+m.attacks[i].INUM+'"></span>&nbsp;\
				<input class="mob-attack attack-damroll-'+n+'" inum="'+m.attacks[i].INUM+'" data="Damroll" type="text" style="width: 20px" value="'+m.attacks[i].Damroll+'">\
				+ <input class="mob-attack attack-nodice-'+n+'" inum="'+m.attacks[i].INUM+'" data="NoDice" type="text" style="width: 20px" value="'+m.attacks[i].NoDice+'">\
				dice of <input class="mob-attack attack-sizedice-'+n+'" inum="'+m.attacks[i].INUM+'" data="SizeDice" type="text" style="width: 20px" value="'+m.attacks[i].SizeDice+'"> sides \
				<select class="attack-type attack-type-'+n+'" data="'+m.attacks[i].INUM+'">\
					<option value="0">hit</option>\
					<option value="1">slash</option>\
					<option value="3">trash</option>\
					<option value="5">crush</option>\
					<option value="6">pound</option>\
					<option value="11">strike</option>\
					<option value="12">pierce</option>\
					<option value="13">whip</option>\
					<option value="16">stab</option>\
					<option value="17">pummel</option>\
					<option value="18">smite</option>\
					<option value="21">sting</option>\
					<option value="22">bite</option>\
					<option value="23">bludgeon</option>\
					<option value="24">claw</option>\
					<option value="25">maul</option>\
					<option value="26">blast</option>\
					<option value="27">punch</option>\
				</select></span>\
				<span class="left">&nbsp;Speed:&nbsp;-&nbsp;</span><div data="'+m.attacks[i].INUM+'" class="left attack-speed-'+n+'" style="width: 90px"></div><span class="left">&nbsp;+</span></div>\
			');
			
		$('.attack-type-'+n).val(m.attacks[i].Type);
		$('.attack-speed-'+n).slider({
			value: 1,
			min: 1,
			max: 100,
			stop: function() { for (var i in m.attacks) if (m.attacks[i].INUM == $(this).attr('data')) { m.attacks[i].Attacks = (101-$(this).slider('option', 'value')).toString() } }
		});
		$('.attack-speed-'+n).slider('option', 'value', 101 - m.attacks[i].Attacks);
		n++;
	}
}
function mobAttackSet(id, param, value) {
	for (var i in m.attacks) { if (m.attacks[i].INUM == id) m.attacks[i][param] = value }
}
function mobAttackAdd(vnum) {
  var a = 0;
	for (var i in m.attacks) {
		if (m.attacks[i].VNUM == vnum) {
			var t = m.attacks[i].INUM.split('.')[1].toInt();
			if (t == a) a++;
		}
	}
	m.attacks.push({
		INUM: vnum.toString()+'.'+a,
		VNUM: vnum.toString(),
		NoDice: '1',
		SizeDice: '1',
		Damroll: '1',
		Type: '0',
		Attacks: '100'
	});
	m.attacks = sortHash(m.attacks, 'INUM');
	mobLoad(vnum);
	$('#mob-progs-accordion').accordion("activate", a);
}
function mobAttackDelete(inum) {
	for (var i in m.attacks)
		if (m.attacks[i].INUM == inum) {
			m.attacks.splice(i, 1);
			mobLoad(m.data[M].VNUM);
			return;
		}
}
function mobObjectsLoad(mnum) {
	var html = '<span class="left ui-icon ui-icon-circle-plus mob-object-add"></span>&nbsp;<b>Loads:</b><br><br>';
	for (var i in m.objects) {
		if (m.objects[i].MNUM != mnum) continue;
			html += '<div id="mob-object-'+m.objects[i].INUM+'">\
			<span class="left ui-icon ui-icon-circle-close mob-object-delete" inum="'+m.objects[i].INUM+'"></span>\
			<span class="left">&nbsp;'+buildMobObjSelect(m.objects[i].ONUM, m.objects[i].INUM, 'mob-object-number mob-object-'+m.objects[i].NUM)+'</span>';
			if (m.objects[i].ONUM.slice(0, -2) == z.data[Z].VNUM)
				html += '&nbsp;<span class="left ui-icon ui-icon-pencil" onclick="objLoad($(\'.mob-object-'+m.objects[i].NUM+'\').val())"></span>&nbsp;';
			html += '<span class="left">&nbsp;<select class="mob-object-position" inum="'+m.objects[i].INUM+'">';
				for (var p in obj_positions) {
					if (m.objects[i].Position == obj_positions[p].a) 
						html += '<option value="'+obj_positions[p].a+'" selected="selected">'+obj_positions[p].b+'</option>';
					else
						html += '<option value="'+obj_positions[p].a+'">'+obj_positions[p].b+'</option>';
				}

			html += '</select></span><span class="left">&nbsp;\
				% Load: <input class="mob-object" data="Chance" type="text" style="width: 26px" value="'+m.objects[i].Chance+'">\
				Max: <input class="mob-object" data="Max" type="text" style="width: 26px" value="'+m.objects[i].Max+'"></span></div><div style="clear:both"></div>';
	}
	$('#mob-objects').html(html);
}
function mobObjectSet(id, param, value) {
	for (var i in m.objects) { if (m.objects[i].INUM != id) continue; m.objects[i][param] = value }
}
function mobObjectAdd(vnum) {
  var a = 0;
	for (var i in m.objects) {
		if (m.objects[i].VNUM == vnum) {
			var t = m.objects[i].INUM.split('.')[1].toInt();
			if (t == a) a++;
		}
	}
	m.objects.push({
		INUM: vnum.toString()+'.'+a,
		MNUM: vnum.toString(),
		ONUM: o.data[0].VNUM,
		NUM: a.toString(),
		Chance: '50',
		Position: '-1',
		Max: '10'
	});
	m.objects = sortHash(m.objects, 'INUM');
	mobLoad(vnum);
}
function mobObjectDelete(inum) {
	for (var i in m.objects)
		if (m.objects[i].INUM == inum) {
			m.objects.splice(i, 1);
			mobLoad(inum.split('.')[0]);
			return;
		}
}
function mobProgsLoad(vnum) {
	var html = '<span class="left ui-icon ui-icon-circle-plus prog-add"></span>&nbsp;<b>Mobprogs:</b><span class="right"><a href="../mobprogs.php" target="_blank">examples</a></span><br><br><div id="mob-progs-accordion">';
	var n = 1;
	for (var i in m.progs) 
		if (m.progs[i].VNUM == vnum) {
			html += '<h3><a href="#">Prog #'+n+'</a></h3><div id="mob-prog-'+m.progs[i].INUM+'">\
				<span class="left ui-icon ui-icon-circle-close prog-delete" inum="'+m.progs[i].INUM+'"></span>&nbsp;\
				Type:\
				<select class="prog-type" data="'+m.progs[i].INUM+'">';
			
			for (var p in mob_progs) {
				if (mob_progs[p] == m.progs[i].Type)
					html += '<option value="'+mob_progs[p]+'" selected="selected">'+mob_progs[p]+'</option>';
				else
					html += '<option value="'+mob_progs[p]+'">'+mob_progs[p]+'</option>';
			}
					
			html += '</select> Args:\
				<input class="prog-args" type="text" style="width: 160px" value="'+m.progs[i].ArgList+'" data="'+m.progs[i].INUM+'"><div class="sep"></div>\
				<textarea class="prog-commands" cols="70" rows="10" style="font-size: 10px" data="'+m.progs[i].INUM+'">'+m.progs[i].Commands+'</textarea>\
				</div>';
				
			n++;
		}
	$('#mob-progs').html(html + '</div>');
	$('#mob-progs-accordion').accordion();
}
function mobProgAdd(vnum) {
  var a = 0;
	for (var i in m.progs) {
		if (m.progs[i].VNUM == vnum) {
			var t = m.progs[i].INUM.split('.')[1].toInt();
			if (t == a) a++;
		}
	}
	m.progs.push({
		INUM: vnum.toString()+'.'+a,
		VNUM: vnum.toString(),
		Type: '0',
		ArgList: '',
		Commands: ''
	});
	m.progs = sortHash(m.progs, 'INUM');
	mobLoad(vnum);
}
function mobProgDelete(inum) {
	for (var i in m.progs)
		if (m.progs[i].INUM == inum) {
			m.progs.splice(i, 1);
			mobLoad(inum.split('.')[0]);
			return;
		}
}
function mobShopLoad(vnum) {
  var shop = shopFind(vnum);
  $('#mob-shop').html('');
	if (shop > -1) {
		var html = '<span class="left ui-icon ui-icon-circle-close" onclick="mobShopDelete('+s.data[shop].SNUM+')"></span>&nbsp;<b>Shopkeeper:</b> sells at <input class="mob-buy-profit" style="width: 30px" snum="'+s.data[shop].SNUM+'" value="'+Math.round(s.data[shop].BuyProfit*100)+'"> %, buys at <input class="mob-sell-profit" style="width: 24px" snum="'+s.data[shop].SNUM+'" value="'+Math.round(s.data[shop].SellProfit*100)+'"> %<br><br>';
		
		html += '<div class="indent"><span class="left ui-icon ui-icon-circle-plus" onclick="mobProductAdd(\''+s.data[shop].SNUM+'\')"></span><span class="ui-tooltip" title="The items a shopkeeper produces will be unlimited in quantity. Each has to be set to load on the mob in order to be available.">&nbsp;Produces:</span><br><br>';
		
		for (var i in s.products) 
			if (s.products[i].SNUM == s.data[shop].SNUM) {
				html += '<span class="left ui-icon ui-icon-circle-close" onclick="mobProductDelete(\''+s.products[i].INUM+'\')"></span>\
				<span class="left">&nbsp;'+buildMobObjSelect(s.products[i].ONUM, s.products[i].INUM, 'mob-product-select')+'</span>';
				if (vnum.slice(0, -2) == z.data[Z].VNUM)
				html += '&nbsp;<span class="left ui-icon ui-icon-pencil" onclick="objLoad($(\'.mob-product-select\').val())"></span>';
				html += '<div id="c"></div>';
			}
		
		html += '<br><br>';
		
		html += '<span class="left ui-icon ui-icon-circle-plus" onclick="mobTypeAdd(\''+s.data[shop].SNUM+'\')"></span><span class="ui-tooltip" title="List item types that a shopkeeper will buy. For each type, optionally specify keywords this item type should match. For example: silver gold".">&nbsp;Will buy:</span><br><br>';
		
		for (var i in s.buys) 
			if (s.buys[i].SNUM == s.data[shop].SNUM) {
				html += '<span class="left ui-icon ui-icon-circle-close" onclick="mobTypeDelete('+s.buys[i].INUM+')"></span>&nbsp;';
				html += buildBuyType(s.buys[i].INUM, s.buys[i].OTYPE);
				html += ' with keywords: <input id="mob-buy-keywords" type="text" style="width: 160px" value="'+((s.buys[i].Keywords != '(null)')?s.buys[i].Keywords:'')+'" inum="'+s.buys[i].INUM+'"><div style="clear:both"></div>';
			}
			
		html += '</div><br>';
		
		$('#mob-shop').html(html);
	}
	else $('#mob-shop').html('<span class="left ui-icon ui-icon-circle-plus" onclick="mobShopAdd('+vnum+')"></span>&nbsp;<b>Shopkeeper:</b><br>');
}
function mobShopAdd(mnum) {
var snum = getFree(s.data, 'SNUM');
var rnum = '';
	for (var i in z.reset)
		if (z.reset[i].Command == 'M' && z.reset[i].Arg1 == mnum) rnum = z.reset[i].Arg3;
	
	s.data.push({
		"SNUM": snum,
		"ShopKeeper": mnum,
		"BuyProfit": "1.2",
		"SellProfit": "0.8",
		"BitVector": "0",
		"TradeWith": "0",
		"BrokeTemper": "0",
		"Open1":"0",
		"Close1":"28",
		"Open2":"0",
		"Close2":"0",
		"NoSuchItem1":"%s Haven't got that on storage - try list!",
		"NoSuchItem2":"%s I don't have that.",
		"DoNotBuy":"%s I don't buy these.",
		"MissingCash1":"%s I can't afford that.",
		"MissingCash2":"%s You don't have enough money.",
		"MessageBuy":"%s That'll be %d coins.",
		"MessageSell":"%s Oops - %d a minor bug - please report!",
		"RNUM": rnum
	});
	
	s.buys.push({
		"OTYPE":"0",
		"Keywords":"(null)",
		"INUM":snum+".0",
		"NUM":"0",
		"SNUM":snum
	});
	
	s.data = sortHash(s.data, 'INUM');
	s.buys = sortHash(s.buys, 'INUM');
	
	mobLoad(mnum);
}
function mobShopDelete(snum) {
	for (var i in s.products)
		if (s.products[i].SNUM == snum) { s.products.splice(i, 1); return }
	for (var i in s.buys)
		if (s.buys[i].SNUM == snum) { s.buys.splice(i, 1); return }
	for (var i in s.data)
		if (s.data[i].SNUM == snum) { s.data.splice(i, 1); return }
	mobLoad(m.data[M].VNUM);
}
function mobProductDelete(inum) {
	for (var i in s.products)
		if (s.products[i].INUM == inum) {
			s.products.splice(i, 1);
			mobLoad(m.data[M].VNUM);
			return;
		}
}
function mobProductAdd(snum) {
  if (!o.data || !o.data.length) return;
  var a = 0;
	for (var i in s.products) {
		if (s.products[i].SNUM == snum) {
			var t = s.products[i].INUM.split('.')[1].toInt();
			if (t == a) a++;
		}
	}
	s.products.push({
		INUM: snum.toString()+'.'+a,
		SNUM: snum.toString(),
		NUM: a,
		ONUM: o.data[0].VNUM
	});
	s.products = sortHash(s.products, 'INUM');
	mobLoad(m.data[M].VNUM);
}
function mobTypeAdd(snum) {
  var a = 0;
	for (var i in s.buys) {
		if (s.buys[i].SNUM == snum) {
			var t = s.buys[i].INUM.split('.')[1].toInt();
			if (t == a) a++;
		}
	}
	s.buys.push({
		INUM: snum.toString()+'.'+a,
		SNUM: snum.toString(),
		NUM: a,
		Type: '0',
		Keywords: '(null)'
	});
	s.buys = sortHash(s.buys, 'INUM');
	mobLoad(m.data[M].VNUM);
}
function mobTypeDelete(inum) {
	for (var i in s.buys)
		if (s.buys[i].INUM == inum) {
			s.buys.splice(i, 1);
			mobLoad(m.data[M].VNUM);
			return;
		}
}
function mobBalance() {
	if ($("*:focus").html() != null) $("*:focus").get(0).blur();
	
	if (!$('#mob-level').val()) {
		showDialog('Mob auto-balance error', 'Enter the mob level so it can be used as a basis.');
		return;
	}
	
	var l = $('#mob-level').val().toInt();
	var vnum = m.data[M].VNUM;
	
	$('#mob-armor').val(parseInt(100-(l*3.2))).trigger('change');
	$('#mob-health').val(parseInt((l*l*l*l)/450)).trigger('change');
	$('#mob-hitroll').slider('option', 'value', parseInt((l*2)/3));
	m.points[M].Hitroll = (20 - parseInt((l*2)/3)).toString();
	$('#mob-exp').val(parseInt(Math.pow(l,4)/10)).trigger('change');
	$('#mob-gold').val(parseInt(Math.pow(l,4)/96)).trigger('change');
	
	if ($('.attack-nodice-0').html() != null) {
		$('.attack-nodice-0').val(parseInt(l/5.4)).trigger('change');
		$('.attack-sizedice-0').val(parseInt(l/3.8)).trigger('change');
		$('.attack-damroll-0').val(parseInt(l/2.6)).trigger('change');
		$('.attack-speed-0').slider('option', 'value', l);
		for (var i in m.attacks) if (m.attacks[i].INUM == vnum + '.0') m.attacks[i].INUM = (l).toString();
	}
	else {
		m.attacks.push({
			INUM: vnum.toString()+'.0',
			VNUM: vnum.toString(),
			NoDice: (parseInt(l/8)).toString(),
			SizeDice: (parseInt(l/6)).toString(),
			Damroll: (parseInt(l/3)).toString(),
			Type: '0',
			Attacks: (20+l).toString()
		});
		m.attacks = sortHash(m.attacks, 'INUM');
		mobLoad(vnum);
	}
}
function mobInit(evt, el) {
	var from = '';
	if (!el) {
		evt = evt?evt:window.event; 
		if (evt.which != 1) return false;
		el = evt.target||evt.srcElement;
	}
	else {
		from = dbr.mob_copy?dbr.mob_copy:dbr.mob_cut;
		if (!from) {
			showDialog('Mobile clone error', 'You have to copy or cut an existing mobile before cloning it.'); 
			return;
		}
		from = mobFind(from);
	}
	
	var vnum = ($('#map-view').val() == 'list')?$(el).attr('vnum'):getFreeVnum(m.data);

	if (vnum == -1) { 
		showDialog('Mobile creation error', 'There are no more free unique mobile numbers in the current area. Delete some first or request another area.'); 
		return;
	}
	
	$(el).attr('vnum', vnum);

	m.data.push({
		VNUM: vnum.toString(),
		Name: from?m.data[from].Name:'New mob',
		Class: from?m.data[from].Class:'0',
		Sex: from?m.data[from].Sex:'0',
		Level: from?m.data[from].Level:'1',
		Descr: from?m.data[from].Descr:'An unfinished mob is here.\r\n',
		LongDescr: from?m.data[from].LongDescr:'',
		Keywords: from?m.data[from].Keywords:'0'
	});
	
	m.data = sortHash(m.data, 'VNUM');
	
	m.special_data.push({
		VNUM: vnum.toString(),
		Align: from?m.special_data[from].Align:'0',
		MobFlags: from?m.special_data[from].MobFlags:'0',
		AffectedBy: from?m.special_data[from].AffectedBy:'0',
		Position: from?m.special_data[from].Position:'1',
		DefaultPos: from?m.special_data[from].DefaultPos:'8',
		Race: from?m.special_data[from].Race:'0'		
	});
	
	m.points.push({
		VNUM: vnum.toString(),
		Hit1: from?m.points[from].Hit1:'0',
		Hit2: from?m.points[from].Hit2:'0',
		BaseHit: from?m.points[from].BaseHit:'0',
		Armor: from?m.points[from].Armor:'0',
		Gold: from?m.points[from].Gold:'0',
		Exp: from?m.points[from].Exp:'0',
		Hitroll: from?m.points[from].Hitroll:'0',
		Damroll: from?m.points[from].Damroll:'0'
	});
	
	m.abilities.push({
		VNUM: vnum.toString(),
		Str: from?m.points[from].Str:'11',
		StrAdd: from?m.points[from].StrAdd:'11',
		Intel: '11',
		Wis: '11',
		Dex: '11',
		Con: '11',
		Cha: '11'
	});
	
	if (!from)
		m.attacks.push({
			INUM: vnum.toString()+'.0',
			VNUM: vnum.toString(),
			NoDice: '1',
			SizeDice: '1',
			Damroll: '1',
			Type: '0',
			Attacks: '100'
		});
	else {
		for (var i in m.attacks)
			if (m.attacks[i].VNUM == m.data[from].VNUM)
				m.attacks.push({
					INUM: vnum.toString()+'.0',
					VNUM: vnum.toString(),
					NoDice: m.attacks[i].NoDice,
					SizeDice: m.attacks[i].SizeDice,
					Damroll: m.attacks[i].Damroll,
					Type: m.attacks[i].Type,
					Attacks: m.attacks[i].Attacks
				});
	}
	
	loadMobGrid();
	$('#mob-'+vnum).trigger({ type: 'mousedown', which: 1 });
}

function mobMove(el) {
	var from = dbr.mob_copy?dbr.mob_copy:dbr.mob_cut;
	var to = $(el).attr('id').split('-')[1];
	var i;

	if (!from) {
		showDialog('Mobile move error', 'You have to copy or cut an existing mobile before moving it.'); 
		return;
	}
		from = mobFind(from);
		
	for (i in m.data)
		if (m.data[i].VNUM == from) m.data[i].VNUM = to;
	for (i in m.points)
		if (m.points[i].VNUM == from) m.points[i].VNUM = to;
	for (i in m.special_data)
		if (m.special_data[i].VNUM == from) m.special_data[i].VNUM = to;
	for (i in m.abilities)
		if (m.abilities[i].VNUM == from) m.abilities[i].VNUM = to;
	for (i in m.attacks)
		if (m.attacks[i].VNUM == from) {
			m.attacks[i].VNUM = to;
			m.attacks[i].INUM = to + m.attacks[i].INUM.split('.')[1];
		}
	for (i in m.progs)
		if (m.progs[i].VNUM == from) {
			m.progs[i].VNUM = to;
			m.progs[i].INUM = to + m.progs[i].INUM.split('.')[1];
		}
	for (i in m.objects)
		if (m.objects[i].MNUM == from) {
			m.objects[i].MNUM = to;
			m.objects[i].INUM = to + m.objects[i].INUM.split('.')[1];
		}
	for (i in z.reset) {
		if (z.reset[i].Command == 'M' && z.reset[i].Arg1 == from) z.reset[i].Arg1 = to;
		if (z.reset[i].Command == 'G' && z.reset[i].Arg3 == from) z.reset[i].Arg3 = to;
	}
}
function mobDelete(vnum) {
	var i, scan;	
	for (i in m.data)
		if (m.data[i].VNUM == vnum) m.data.splice(i, 1);
	for (i in m.points)
		if (m.points[i].VNUM == vnum) m.points.splice(i, 1);
	for (i in m.special_data)
		if (m.special_data[i].VNUM == vnum) m.special_data.splice(i, 1);
	for (i in m.abilities)
		if (m.abilities[i].VNUM == vnum) m.abilities.splice(i, 1);
	for (i in m.attacks)
		if (m.attacks[i].VNUM == vnum) {
			m.attacks.splice(i, 1);
			i--;
		}
	for (i in m.progs)
		if (m.progs[i].VNUM == vnum) {
			m.progs.splice(i, 1);
			i--;
		}
	for (i in m.objects)
		if (m.objects[i].MNUM == vnum) {
			m.objects.splice(i, 1);
			i--;
		}
	for (i in z.reset) {
		if (z.reset[i].Command == 'G' && z.reset[i].Arg3 == vnum) { z.reset.splice(i, 1); i-- }
		if (z.reset[i].Command == 'M' && z.reset[i].Arg1 == vnum) {
			z.reset.splice(i, 1);
			i--;
			scan = true;
		}
		if (scan) {
			if (z.reset[i].Command == 'M') scan = false;
			if (z.reset[i].Command == 'E') { z.reset.splice(i, 1); i-- }
		}
	}
}
function objLoad(vnum) {

	if ($("*:focus").html() != null) $("*:focus").get(0).blur();
	$("#data").tabs('select', '#data_objs');
	
	$('.oicon').removeClass('ui-state-active');
	$('#obj-'+vnum).addClass('ui-state-active');
	
	//$('#obj-flags').multiselect('uncheckAll');
	//$('#obj-extra').multiselect('uncheckAll');
	
	O = objFind(vnum);
	
	$('#obj-id').val(o.data[O].VNUM);
	$('#obj-name').val(o.data[O].ShortDesc);
	$('#obj-keywords').val(o.data[O].Keywords);
	$('#obj-type').selectmenu('value', o.data[O].Type.toString());
	$('#obj-weight').val(o.data[O].Weight);
	$('#obj-material').selectmenu('value', o.data[O].Val4);
	o.data[O].WearFlags.toFlag('#obj-worn');
	o.data[O].ExtraFlags.toFlag('#obj-extra');
	o.data[O].BitVector.toFlag('#obj-aff');
	
	$('#obj-value').val(o.data[O].Cost);
	$('#obj-cost').val(o.data[O].CostPerDay);
	
	$('#obj-short').val(o.data[O].Descr.stripBreaks());
	objTypeChange();
	
	$('#obj-apply-form').html('<table style="width: 80%"><tr><td class="obj-col-0"></td><td class="obj-col-1"></td></tr></table>');
	var c = 0
	
	for (var i = 0; i < 6; i++) {
		$('.obj-col-'+c).append('<input class="obj-input" data="Mod'+i+'" type="text" style="width: 28px" value="'+o.data[O]['Mod'+i].toInt()+'"> to ' + buildApplySelect(i, o.data[O]['Aff'+i].toInt()) + '<br>');
		c = 1 - c;
	}
	
	if ($('#obj-apply-button').hasClass('collapsed'))
		$('#obj-apply-form').hide();
	
	objLoadDescriptions(vnum);
}
function objLoadDescriptions(vnum) {
	$('#obj-desc').html('<span class="left ui-icon ui-icon-circle-plus obj-desc-add"></span>&nbsp;<span class="ui-tooltip" title="additional item descriptions when the user looks at or examines via a keyword"><b>Extra Descriptions:</b></span><br><br>');
	for (var i in o.extra) {
		if (o.extra[i].VNUM == vnum) {
			$('#obj-desc').append('<div id="obj-desc-'+o.extra[i].INUM+'"><span class="left">\
			<span class="left ui-icon ui-icon-circle-close obj-desc-delete" inum="'+o.extra[i].INUM+'"></span><span class="left">&nbsp;\
				Keyword: <input class="obj-desc" inum="'+o.extra[i].INUM+'" data="Keyword" type="text" style="width: 140px" value="'+o.extra[i].Keyword+'"></span><br><br>\
				Description:<textarea class="obj-desc" inum="'+o.extra[i].INUM+'" data="Description" cols="80" rows="5" style="font-size: 11px">'+o.extra[i].Description+'</textarea><br><br></div>');
		}
	}
}
function objDescriptionAdd(vnum) {
  var a = 0;
  if (!o.extra || !o.extra.length) o.extra = [];
	for (var i in o.extra) {
		if (o.extra[i].VNUM == vnum) {
			var t = o.extra[i].INUM.split('.')[1].toInt();
			if (t == a) a++;
		}
	}
	o.extra.push({
		INUM: vnum.toString()+'.'+a,
		VNUM: vnum.toString(),
		NUM: a,
		Keyword: '',
		Description: ''
	});
	o.extra = sortHash(o.extra, 'INUM');
	objLoad(vnum);
}
function objDescriptionDelete(inum) {
	for (var i in o.extra)
		if (o.extra[i].INUM == inum) {
			o.extra.splice(i, 1);
			objLoad(inum.split('.')[0]);
			return;
		}
}
function objInit(evt) {

	//$("#data").tabs('select', '#data_objs');
	
	evt = evt?evt:window.event; 
	if (evt.which != 1) return false;
	var el = evt.target||evt.srcElement;
	
	var vnum;

	if ($('#map-view').val() == 'list')
	vnum = $(el).attr('vnum');
	else vnum = getFreeVnum(o.data);

	if (vnum == -1) { 
		showDialog('Object creation error', 'There are no more free unique object numbers in the current area. Delete some first or request another area.'); 
		return false;
	}

	$(el).attr('vnum', vnum);

	o.data.push({
		VNUM: vnum.toString(),
		ShortDesc: 'New object',
		Type: '11',
		Keywords: '',
		Descr: 'An unfinished object is here.\r\n',
		LongDesc: '',
		WearFlags: '1',
		ExtraFlags: '0',
		BitVector: '0',
		Cost: '0',
		CostPerDay: '0',
		Val0: '0',
		Val1: '0',
		Val2: '0',
		Val3: '0',
		Val4: '0',
		Sval0: '0',
		Sval1: '0',
		Sval2: '0',
		Aff0: '0',
		Mod0: '0',
		Aff1: '0',
		Mod1: '0',
		Aff2: '0',
		Mod2: '0',
		Aff3: '0',
		Mod3: '0',
		Aff4: '0',
		Mod4: '0',
		Aff5: '0',
		Mod5: '0',
	});
	
	o.data = sortHash(o.data, 'VNUM');
	
	loadObjGrid('#obj-'+vnum);
	$('#obj-'+vnum).trigger({ type: 'mousedown', which: 1 });
}

function objTypeChange() {

	if ($('#obj-type').val() == 5) {
		$('#v0-label').html('');
		$('#v1-label').html('<input id="obj-v1" type="text" style="width: 20px" value="'+o.data[O].Val1+'">&nbsp;dice of');
		$('#v2-label').html('&nbsp<input id="obj-v2" type="text" style="width: 20px" value="'+o.data[O].Val2+'">&nbsp;sides');
		$('#v3-label').html('&nbsp;'+buildWeaponSelect(o.data[O].Val3));
	}
	else if ($.inArray($('#obj-type').val(), ['2','3','4','10']) != -1) {
		$('#v0-label').html('Lvl:&nbsp;<input id="obj-v0" type="text" value="'+o.data[O].Val0+'" style="width: 24px">&nbsp;');
		$('#v1-label').html('<div class="sep"></div>Casts:&nbsp;'+buildSpellSelect(1, o.data[O].Val1));
		$('#v2-label').html(buildSpellSelect(2, o.data[O].Val2));
		$('#v3-label').html(buildSpellSelect(3, o.data[O].Val3));
	}
	else if ($('#obj-type').val() == 9) {
		$('#v0-label').html('AC Apply:&nbsp;<input id="obj-v0" type="text" style="width: 24px" value="'+o.data[O].Val0+'">');
		$('#v1-label').html('');
		$('#v2-label').html('');
		$('#v3-label').html('');
	}
	else if ($('#obj-type').val() == 15) {
		$('#v0-label').html('Capacity:&nbsp;<input id="obj-v0" type="text" style="width: 24px" value="'+o.data[O].Val0+'">');
		$('#v1-label').html('');
		$('#v2-label').html('');
		$('#v3-label').html('');
	}
	else if ($('#obj-type').val() == 19) {
		$('#v0-label').html('How filling (1-24):&nbsp;<input id="obj-v0" type="text" style="width: 24px" value="'+o.data[O].Val0+'">');
		$('#v1-label').html('');
		$('#v2-label').html('');
		$('#v3-label').html('');
	}
	else if ($('#obj-type').val() == 1) {
		$('#v0-label').html('');
		$('#v1-label').html('');
		$('#v2-label').html('Hours (-1 for perm.):&nbsp;<input id="obj-v2" type="text" style="width: 24px" value="'+o.data[O].Val2+'">');
		$('#v3-label').html('');
	}
	else if ($('#obj-type').val() == 17 || $('#obj-type').val() == 23) {
		$('#v0-label').html('Max: <input id="obj-v0" type="text" style="width: 24px" value="'+o.data[O].Val0+'">');
		$('#v1-label').html('Contains: <input id="obj-v1" type="text" style="width: 24px" value="'+o.data[O].Val1+'">');
		$('#v2-label').html('&nbsp;');
		$('#v3-label').html(buildLiquidSelect(o.data[O].Val3));
	}
	else if ($.inArray($('#obj-type').val(), ['0','8','11','12','13','16','18','20','22','24']) != -1) {
		$('#v0-label').html('');
		$('#v1-label').html('');
		$('#v2-label').html('');
		$('#v3-label').html('');
	}	
	else {
		$('#v0-label').html('<input id="obj-v0" type="text" value="'+o.data[O].Val0+'" style="width: 30px">&nbsp');
		$('#v1-label').html('<input id="obj-v1" type="text" value="'+o.data[O].Val1+'" style="width: 30px">&nbsp');
		$('#v2-label').html('<input id="obj-v2" type="text" value="'+o.data[O].Val2+'" style="width: 30px">&nbsp');
		$('#v3-label').html('<input id="obj-v3" type="text" value="'+o.data[O].Val3+'" style="width: 30px">&nbsp');
	}
}

function save(obj, where) {

	globalProgress('Saving to database...');
	
	if (!obj) {
		if (where.has('r')) {
			if (r.data) save(r.data, 'RoomData');
			if (r.exits) save(r.exits, 'RoomExits');
		}
		if (where.has('m')) {
			if (m.data) {
				save(m.data, 'MobData');
				save(m.special_data, 'MobSpecialData');
				save(m.objects, 'MobObjects');
				save(m.attacks, 'MobAttacks');
				save(m.points, 'MobPoints');
				save(m.abilities, 'MobAbilities');
			}
			if (m.progs) save(m.progs, 'MobProgs');
			if (s.data) save(s.data, 'ShopData');
			if (s.buys) save(s.buys, 'ShopBuyTypes');
			if (s.products) save(s.products, 'ShopProducts');
		}
		if (where.has('o')) {
			if (o.data) save(o.data, 'ObjectData');
			if (o.extra) save(o.extra, 'ObjectExtraDescriptions');
		}
		if (where.has('z')) {
			if (z.reset) save(z.reset, 'ZoneReset');
		}
	}
	
	if (exists(obj) && obj && obj.length)
		$.ajax({
		  type: 'POST',
		  url: 'controller.php?task=put&t='+where,
		  data: JSON.stringify(obj),
		  dataType: 'json',
		  success: function(data) {
			globalProgress();
			data.response.hasError();
		  }
		});
}

function roomFind(vnum) { for (var i = 0; i < r.data.length; i++) if (r.data[i].VNUM==vnum) return i; return -1 }
function mobFind(vnum) { for (var i = 0; i < m.data.length; i++) if (m.data[i].VNUM==vnum) return i; return -1 }
function objFind(vnum) { for (var i = 0; i < o.data.length; i++) if (o.data[i].VNUM==vnum) return i; return -1 }
function objFindExtra(inum) { for (var i = 0; i < o.extra.length; i++) if (o.extra[i].INUM==inum) return i; return -1 }
function shopFind(vnum) { for (var i = 0; i < s.data.length; i++) if (s.data[i].ShopKeeper==vnum) return i; return -1 }

function zonePublish() {
	if (!Z) return;
	globalProgress(z.data[Z].Name+': publishing to production...');
	$.get('controller.php?task=publish&id=' + z.data[Z].VNUM, function(data) { globalProgress() });
}
function zoneSync() {
	if (!Z) return;
	globalProgress(z.data[Z].Name+': restoring production version...');
	$.get('controller.php?task=sync&id=' + z.data[Z].VNUM, function(data) { globalProgress(); loadZone(Z) });
}
function zoneResetDelete(lnum) {
	for (var i = 0; i < z.reset.length; i++)
		if (i == lnum) {
			z.reset.splice(i, 1);
				for (var i = 0; i < z.reset.length; i++)
					z.reset[i].LNUM = i.toString();
			return;
		}
}
/* entity icons */
function loadSettings(A) {
	 A = A.split('\n');
	 var n = 0, mi, oi, ri;
	 for (var i = 0; i < A.length; i++) {
		//if (dev) alert(A[i]);
	   if (A[i].has('//NPC')) { mi=true }
	   else if (A[i].has('//OBJ')) { mi=false; oi=true }
	   else if (A[i].has('//ROOM')) { mi=oi=false; ri=true }
		 if (!A[i] || A[i].indexOf('//') == 0 || A[i].indexOf('|') == -1) continue;
										 //if (dev) alert(A[i]);
		 var line = A[i].split('|');//if (dev) alert(line[0]);
		 var key = line[0].split('_')[1];
		 if (!key) continue;
			 if (mi) {
				  mob_images[key] = line[1];
				  mob_index.push(key);
									 //if (dev) alert(key);
			  }
			  else if (oi) {
				  obj_images[key] = line[1];
				  obj_index.push(key);
			  }
			  else if (ri) {
				  room_images[key] = line[1];
				  room_index.push(key);
			  }
	 }
}

function getMobPic(A) {
 if (!mob_images) return;
 A = A.toLowerCase();
 for (var n in mob_index) {
	 var mob = mob_index[n];
	 if (!mob_images[mob] || !mob_images[mob].length) continue;
	 var l = mob_images[mob].split(',');
	 for (var i in l) 
		if (A.has(l[i])) return 'creatures/' + mob;
 }
 return 'hub/default.png';
}

function getObjPic(A) {
 if (!obj_images) return;
 A = A.toLowerCase();
 for (var n in obj_index) {
	 var obj = obj_index[n];
	 if (!obj_images[obj] || !obj_images[obj].length) continue;
	 var l = obj_images[obj].split(',');
	 for (var i in l) 
			if (A.has(l[i])) return 'objects/obj.' + obj;
 }
 return 'hub/default.png';
}

function getRoomPic(A) {
 if (!room_images) return;
 A = A.toLowerCase();
 for (var n in room_index) {
	 var me = room_index[n];
	 if (!room_images[me] || !room_images[me].length) continue;
	 var l = room_images[me].split(',');
	for (var i in l) 
		if (A.has(l[i])) return 'rooms/' + me;
 }
 return 'rooms/room.dungeon.3.jpg';
}

function buildMobSelect() {
	var html = '<select id="arg1">\n';
	for (i in m.data)
		html += '<option value="'+m.data[i].VNUM+'">'+m.data[i].VNUM.slice(-2)+': '+m.data[i].Name+'</option>\n';
	return html + '</select>';
}

function buildObjSelect(room) {
	var html = '<select class="obj-select" id="arg'+(room?'3':'1')+'">\n';
	if (!room)
		for (i in o.data)
			html += '<option value="'+o.data[i].VNUM+'">'+o.data[i].VNUM.slice(-2)+': '+o.data[i].ShortDesc+'</option>\n';
	else
		for (i in z.reset)
			if (z.reset[i].Command == 'O' && z.reset[i].Arg3 == room)
				html += '<option value="'+z.reset[i].Arg1+'">'+z.reset[i].Arg1.slice(-2)+': '+o.data[objFind(z.reset[i].Arg1)].ShortDesc+'</option>\n';
	return html + '</select>';
}

function buildMobObjSelect(vnum, inum, cls) {
	var html = '<select style="width: '+(cls.has('product')?'380':'230')+'px" class="'+cls+'" inum="'+inum+'">\n';
	if (vnum.slice(0, -2) != z.data[Z].VNUM)
		for (i in objects)
			if (objects[i].v == vnum) 
				html += '<option value="'+vnum+'" selected="selected">'+vnum+': ' + objects[i].d + '</option>\n';

	for (i in o.data)
		if (o.data[i].VNUM == vnum)
			html += '<option value="'+o.data[i].VNUM+'" selected="selected">'+o.data[i].VNUM.slice(-2)+': '+o.data[i].ShortDesc+'</option>\n';
		else
			html += '<option value="'+o.data[i].VNUM+'">'+o.data[i].VNUM.slice(-2)+': '+o.data[i].ShortDesc+'</option>\n';
		
	return html + '</select>';
}

function buildWeaponSelect(selected) {
	var html = '<select id="weapon-type">\n';
		for (var i in weapon_type)
			html += '<option value="'+i+'" '+(i==selected?'selected="selected"':'')+'>'+weapon_type[i]+'</option>\n';
	return html + '</select>';
}
function buildApplySelect(id, selected) {
	var html = '<select class="obj-input" data="Aff'+id+'">\n';
		for (var i in apply_type)
			if (apply_type[i])
				html += '<option value="'+i+'" '+(i==selected?'selected="selected"':'')+'>'+apply_type[i]+'</option>\n';
	return html + '</select>';
}
function buildSpellSelect(id, selected) {
	var html = '<select id="obj-v'+id+'" style="width: 150px">\n';
		for (var i in spells)
			html += '<option value="'+spells[i].NUM+'" '+(spells[i].NUM==selected?'selected="selected"':'')+'>'+spells[i].Name+'</option>\n';
	return html + '</select>';
}
function buildLiquidSelect(id, selected) {
	var html = '<span class="left">&nbsp;<select id="obj-v3">';
		for (var p in obj_liquids) {
			if (selected == obj_liquids[p].a) 
				html += '<option value="'+obj_liquids[p].a+'" selected="selected">'+obj_liquids[p].b+'</option>';
			else
				html += '<option value="'+obj_liquids[p].a+'">'+obj_liquids[p].b+'</option>';
		}
	return html + '</select></span>';
}

function buildBuyType(inum, selected) {
	var buy_types = ['','Light','Scroll','Wand','Staff','Weapon','','','Treasure','Armor','Potion','Worn','Other','Trash','','Container','Note','Drink Cont.','','Food','Money','Pen','Boat','Fountain','Trophy'];
	var html = '<select id="mob-buy-type" style="width: 100px" inum="'+inum+'">';
	for (var i in buy_types)
		if (buy_types[i])
			html += '<option value="'+i+'" '+((i==selected)?'selected="selected"':'')+'>'+buy_types[i]+'</option>\n';
	return html + '</select>';
}
/* event indicators & dialogs */
function globalProgress(arg) {
	hideDialog();
	if (arg) {
		globalProgress();
		id('popup-wrapper').innerHTML = '<div id="progress"><br><br><div id="progress-msg">' + ((typeof arg == 'string' && arg)?arg:'') + '</div><br><img class="ui-corner-all" src="css/custom-theme/images/progress-bar.gif"></div>';
		$('#progress').dialog({
			modal: true,
			width: 500,
			height: 160,
			dialogClass: 'alert',
			resizable: false,
			closeOnEscape: true
		});
	} else {
		$('#progress').dialog('destroy');
		$('#progress').remove();
		contextReset();
	}
}
function loginPrompt(title, error) {
	
	globalProgress();
	
	id('popup-wrapper').innerHTML = '<div id="login" title="' + title + '">\
		<div class="hidden ui-state-error"><div class="ui-state-error-text"></div></div>\
		<table style="width: 300px; text-align: left" cellspacing="10">\
		<tr>\
			<td><strong>Builder:&nbsp;</strong></td>\
			<td><input id="char" type="text" size=20></td>\
		</tr>\
		<tr>\
			<td><strong>Password:&nbsp;</strong></td>\
			<td><input id="pass" type="password" size=20></td>\
		</tr>\
		<tr>\
		<td colspan=2>\
			<em><br><a href="mailto:bedlam@eyecandid.com?subject=Bedlam Areabuilder Access">email us</a> to apply for builder access.</em>\
		</td>\
		</tr>\
	</table>\
	</div>';
	
	$('#login').dialog({ 
		width: 400, 
		height: 270,
		modal: true,
		resizable: false,
		closeOnEscape: false,
		show: 'fade',
		buttons: { 
			"Login": function() {
				loginPerform();
			} 
		} 
	});
	
	$('.ui-dialog-titlebar-close').hide();
	
	if (error) {
		$('#login .ui-state-error').show();
		$('#login .ui-state-error-text').html(error);
	}
	
	$('#login #pass').bind('keypress', function(e){
		if (e.keyCode == 13) loginPerform();
	});

}
function loginPerform() {
	$.get('login.php?c='+$('#login #char').val()+'&p='+$('#login #pass').val(), function(data) { loginResponse(data) });
	$('#login').dialog('destroy');
	$('#login').remove();
	globalProgress('Logging in...');
}
function loginResponse(data) {
	if (data.has('Error'))
		loginPrompt(data.split(': ')[0], data.split(': ')[1]);
	else {
	  	globalProgress('Building list of available areas...');
		$.get('controller.php?task=getareas', function(data) { loadZones(data) });
		$.get('controller.php?task=getsettings', function(data) { loadSettings(data) });
		if (data.has('Publisher')) {
			$('.ui-sync').show();
			$('.ui-publish').show();
		}
		$('.ui-logout').removeClass('ui-state-disabled');
		$('.ui-logout').get(0).disabled = false;
		$('.ui-publish').removeClass('ui-state-disabled');
		$('.ui-publish').get(0).disabled = false;
		loadData('spells');
		loadData('objects');
	}
}
function logout() {
	var c = document.cookie.split(";");
	for (var i = 0; i < c.length; i++)
	createCookie(c[i].split("=")[0],"",-1);
		location.reload(true);
}
function showDialog(title, body, h) {
	globalProgress();
	document.body.innerHTML += '<div id="dialog" title="'+title+'"><p>'+body+'</p><br></div>';
	$('#dialog').dialog({ 
		width: 520, 
		height: (exists(h)?h:220), 
		buttons: { 
			"OK": function() { 
				$(this).dialog('destroy');
				$('#dialog').remove();
				contextReset();
			} 
		} 
	});
}
function showLoadMenu() {
	globalProgress();
	$('#main').append('<div id="dialog" title="On-Reset Events for room "'+r.data[R].Name+'"></div>');
	$('#dialog').append('\
		<span class="left">\
		What do you want to do?&nbsp;\
		</span>\
		<span class="left">\
				<select id="command-type">\
					<option value="0">select action</option>\
					<option value="M">Load mobile</option>\
					<option value="O">Load object</option>\
					<option value="P">Put object</option>\
				</select>\
		</span>\
			<div class="sep"></div>\
				<span id="arg1-wrapper"></span>\
				<span id="arg2-wrapper"></span>\
				<span id="arg3-wrapper"></span>\
	');
	$('#dialog').dialog({ 
		width: 500, 
		height: 240, 
		buttons: {
			"Cancel": function() {
				$(this).dialog('destroy');
				$('#dialog').remove();
				contextReset();
			},
			"Add": function() {
				var c = $('.ui-dialog-content #command-type').val();
				if (c == '0') return; 
					z.reset.push({
						IfFlag: '0',
						Command: c,
						Arg1:	$('.ui-dialog-content #arg1').val(),
						Arg2:	c == 'P'?'1':$('.ui-dialog-content #arg2').val(),
						Arg3:	c == 'P'?$('.ui-dialog-content #arg3').val():r.data[R].VNUM,
						LNUM: 	z.reset.length,
						ZNUM:	z.data[Z].VNUM,
						INUM:	z.data[Z].VNUM +'.'+ z.reset.length
					});
				roomLoad(r.data[R].VNUM);
				$(this).dialog('destroy');
				$('#dialog').remove();
				contextReset();
			}
		} 
	});
	//$('.ui-dialog-content #command-type').selectmenu({ type: 'dropdown' });
}
function hideDialog() {
	if (id('dialog')) {
		$('#dialog').dialog('destroy');
		$('#dialog').remove();
	}
}

/* utility functions */
function id(A) { return document.getElementById(A) }
function exists(A) { return (typeof A != 'undefined') }
function center(A) { $(A).css({top:'50%',left:'50%',margin:'-'+($(A).height() / 2)+'px 0 0 -'+($(A).width() / 2)+'px'}) }
function strip_comments(A) { 
	A = A.split('\n');
	B = [];
	for (var i = 0; i < A.length; i++) {
		if (A[i].indexOf('#') == 0) continue;
		B.push(A[i]);
	}
	return B.join('\n').replace('\n\n', '\n');
}
function scanToInt(id) {
	var n = '', o = 0;
	$(id).multiselect("widget").find(":checkbox").each(function(){ 
		while (o < this.value.toInt()) { n += '0'; o++ }
		n += this.checked?'1':'0';
		o++;
	});
	return parseInt(n.reverse(), 2).toString();
}
String.prototype.toFlag = function(id) {
	var f = this.toRevBin();
	if (f) $(id).multiselect("widget").find(":checkbox").each(function(){ if (f[this.value.toInt()] == '1') this.checked=true; else this.checked=false });
}
String.prototype.has = function(A) { return (this.indexOf(A) != -1) }
String.prototype.toInt = function() { return parseInt(this) }
String.prototype.inZone = function(Z) { return (this.toInt() >= (Z*100) && this.toInt() < ((Z+1)*100)) }
String.prototype.hasError = function() { if (this.has('Error: ') && !exists(id('dialog'))) { showDialog(this.split(': ')[0], this.split(': ')[1]); if (this.has('Session expired')) logout(); else return false }}
String.prototype.toRevBin = function () { return this.toInt().toString(2).reverse() }
String.prototype.toBin = function () { return this.toInt().toString(2) }
String.prototype.stripBreaks = function () { return this.replace(/\\n\\r/g, '\r\n') }
String.prototype.format = function () { var a = this; if (a[a.length-1] != '\n' && a[a.length-2] != '\r') a += '\r\n'; if (a[0] != ' ' && a[1] != ' ') a = '   '+a; return a }
String.prototype.splitFields = function(fields) {
	var A = this.split(' ');
	if (A < fields) return '';
	if (A.length > fields) A[fields-1] = A.slice(fields-1).join(' ');
	return A.slice(0, fields);
}
String.prototype.reverse=function(){return this.split("").reverse().join("")}
function sortHash(hash, by) {
  var keys = [], sorted = [];
	for (var i in hash) keys.push(hash[i][by]);
  keys.sort();
	for (var i in keys) 
		for (var n in hash)	
			if (hash[n][by] == keys[i])
				sorted.push(hash[n]);
	return sorted;
}
function round(num, dec) { var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec); return result; }
function getFreeVnum(A) { return getFree(A, 'VNUM') }
function getFree(A, B) {
if (A.length == 100) return -1;
if (!A.length) return (z.data[Z][B].toInt()*100);
  var v, i;
	for (i = 0; i < A.length; i++) {
		v = A[i][B].toInt();
		if (i == (A.length-1))
			{ if ((v+1) < (z.data[Z][B].toInt()+1)*100) return (v+1); }
		else
			if (A[i+1][B].toInt() > (v+1)) return (v+1);
	}
  return -1;
}
function zeroPad(number, limit) { return (Array(limit).join('0') + number).slice(-limit) }
function getExitUp(vnum) {
	for (var i = 0; i < r.exits.length; i++)
		if (r.exits[i].VNUM == vnum && r.exits[i].NUM == '4') return r.exits[i].ToRoom;
	return false;
}
function getExitDown(vnum) {
	for (var i = 0; i < r.exits.length; i++)
		if (r.exits[i].VNUM == vnum && r.exits[i].NUM == '5') return r.exits[i].ToRoom;
	return false;
}
function createCookie(name, value, days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
    }
    else var expires = "";
    document.cookie = name+"="+value+expires+"; path=/areabuilder/";
}