////////////////////////////////////////////////////////////////
// Digital Deadwood Online Game Engine - (c) 2004 
////////////////////////////////////////////////////////////////
// For use only by TDG Communications on www.digitaldeadwood.com
////////////////////////////////////////////////////////////////
// Programmed by Christer Kaitila in PHP and Javascript
// Freelance programmer for hire: http://www.orangeview.net
////////////////////////////////////////////////////////////////
// Additional code credits - many thanks for online tutorials!
////////////////////////////////////////////////////////////////
// http://www.codeproject.net      // http://www.brainjar.com		
// http://www.experts-exchange.com // http://www.w3.org
// http://www.mikefoster.f2s.com   // http://lineoflight.com
// http://www.yasd.com/dynatech    // http://dannyg.com

var dd_v2_debug = false; // if true you get millions of messageboxes

function stopErrors() { return true; }

if (dd_v2_debug) 
{
	if (document.chatform) document.chatform.mychat.value='DEBUG MODE - Starting up...';
	alert('This is the DEBUG engine.\nUse at own risk! =)'); 
}
else
{
	window.onerror = stopErrors;
	document.onerror = stopErrors;
}

var dd_people_count = 0;
var dd_people = new Array();
var dd_people_shootout = new Array(); var maxbadguys = 7;
var NPCSLOT = 99; // dd_people[99] controls player0 - NPC
var currentMouseX, currentMouseY, currentGridX, currentGridY, currentMouseDir, currentMouseDistance;
var Player0,Player1,Player2,Player3,Player4,Player5,Player6,Player7,Player8,Player9,Player10,Player11,Player12,Player13,Player14,Player15,Player16,Player17,Player18,Player19,Player20;
var bub0,bub1,bub2,bub3,bub4,bub5,bub6,bub7,bub8,bub9;
var bub10,bub11,bub12,bub13,bub14,bub15,bub16,bub17,bub18,bub19,bub20;
var window_map, window_journal, window_inventory, window_history, window_slots, window_blackjack, window_shootout, window_shootout_ready, window_shootout_gameover;
var notbusy = true;
var no_warping = false;
var dd_ignore_next_click = false;
var most_recent_anumba = '0';
var shootout_level_prev = -999;
var shootout_score_prev = -999;
var shootout_hits_prev = -999;
var shootout_misses_prev = -999;
var shootout_bullets_prev = -999;
var shootout_time_prev = -999;
var shootout_level = 1;
var shootout_score = 0;
var shootout_hits = 0;
var shootout_misses = 0;
var shootout_bullets = 24;
var shootout_time = 60;
var shootout_paused = true;
var shootout_level_div = 0;
var shootout_score_div = 0;
var shootout_hits_div = 0;
var shootout_miss_div = 0;
var shootout_bull_div = 0;
var shootout_time_div = 0;
var first_shootout_frame = true;
var AVATAR_X_NUDGE = 6;
var AVATAR_Y_NUDGE = -8;

// shootout
var bullethole = new Array();
var maxbulletholes=24;
var bulletholes=0;
var xcursor = false;
var gcursor = false;
var shootout_cover_img = 'cache.php?img=walk_redbadguy_dr_cover.gif';
var shootout_open_img = 'cache.php?img=walk_redbadguy_dr_open.gif';
var shootout_fire_img = 'cache.php?img=walk_redbadguy_dr_fire.gif';
var shootout_hit_img = 'cache.php?img=walk_redbadguy_dr_hit.gif';
var shootout_dead_img = 'cache.php?img=walk_redbadguy_dr_dead.gif';


var destroy_idle_bots = false;
var max_idle_time = 10*60*1000; // 5 minutes
var check_idle_time = 11*60*1000; // 6 minutes

// DD screen movement directions (NUMPAD)
var dirUP=8;
var dirDN=2;
var dirLF=4;
var dirRT=6;
var dirUR=9;
var dirUL=7;
var dirDR=3;
var dirDL=1;
var dirNONE=5;

// Preloaded images that stay in ram
pics=new Array('cache.php?img=fx_blank.gif','cache.php?img=button_map_over.jpg','cache.php?img=button_journal_over.jpg','cache.php?img=button_inventory_over.jpg','cache.php?img=button_history_over.jpg','cache.php?img=button_flip_over.jpg','cache.php?img=button_map_flipped_over.jpg','cache.php?img=button_map_flipped.jpg','cache.php?img=button_inventory_close_over.jpg','cache.php?img=button_inv_over.gif','cache.php?img=button_historylink_close_over.gif','cache.php?img=button_journal_close_over.gif','cache.php?img=bubble.gif',
		'cache.php?img=gui_v4_left_bottom_flipped.gif','cache.php?img=gui_v4_left_bottom.gif','cache.php?img=gui_v4_left_lower.gif','cache.php?img=gui_v4_left_top.gif','cache.php?img=gui_v4_left_top_flipped.gif','cache.php?img=gui_v4_left_upper.gif','cache.php?img=gui_v4_left_lower_flipped.gif','cache.php?img=gui_v4_left_upper_flipped.gif','cache.php?img=gui_v4_right_bottom_flipped.gif','cache.php?img=gui_v4_right_lower.gif','cache.php?img=gui_v4_right_lower_flipped.gif','cache.php?img=gui_v4_right_top.gif','cache.php?img=gui_v4_right_top_flipped.gif','cache.php?img=gui_v4_right_upper.gif','cache.php?img=gui_v4_right_upper_flipped.gif','cache.php?img=gui_v4_right_bottom.gif',
		'cache.php?img=gui_v4_left_bottom_flipped_over.gif','cache.php?img=gui_v4_left_bottom_over.gif','cache.php?img=gui_v4_left_lower_over.gif','cache.php?img=gui_v4_left_top_over.gif','cache.php?img=gui_v4_left_top_flipped_over.gif','cache.php?img=gui_v4_left_upper_over.gif','cache.php?img=gui_v4_left_lower_flipped_over.gif','cache.php?img=gui_v4_left_upper_flipped_over.gif','cache.php?img=gui_v4_right_bottom_flipped_over.gif','cache.php?img=gui_v4_right_lower_over.gif','cache.php?img=gui_v4_right_lower_flipped_over.gif','cache.php?img=gui_v4_right_top_over.gif','cache.php?img=gui_v4_right_top_flipped_over.gif','cache.php?img=gui_v4_right_upper_over.gif','cache.php?img=gui_v4_right_upper_flipped_over.gif','cache.php?img=gui_v4_right_bottom_over.gif');

function dd_replace_html(thisid,newhtml)
{
	if (!thisid) return;
	if (!newhtml) return;
	changeme = document.getElementById(thisid);
	if (changeme) changeme.innerHTML=newhtml;
}
function dd_replace_img(thisid,newsrc)
{
	if (!thisid) return;
	if (!newsrc) return;
	changeme = document.getElementById(thisid);
	if (changeme) changeme.src=newsrc;
}
function html_wav(thiswav)
{
	if (!thiswav) return;
	thestring = '<embed src="'+thiswav+'" autostart=true controls=false controller=false hidden=true loop=false height=2 width=0 volume=100>';
	//<NOEMBED><BGSOUND src="file.wav"></noembed>
	return thestring;
}
function dd_wav(thiswav)
{
	dd_replace_html('dd_wav_id',html_wav(thiswav));
}
function sfxreload() { dd_wav('wav/reload.wav'); }
function sfxbang() { dd_wav('wav/bang.wav'); }
function sfxricco() { dd_wav('wav/ricco.wav'); }
function sfxgotme() { dd_wav('wav/gotme.wav'); }
function sfxpickup() { dd_wav('wav/pickup.wav'); }
function sfxdrop() { dd_wav('wav/drop.wav'); }
function sfxclick() { dd_wav('wav/click.wav'); }
function sfxwin() { dd_wav('wav/win.wav'); }
function sfxlose() { dd_wav('wav/lose.wav'); }
function sfxcoin() { dd_wav('wav/coin.wav'); }

function dd_select_warp(meme) 
{ 
	if (!meme) return;
	where = meme.options[meme.selectedIndex].value;
	if (dd_v2_debug) alert('DEBUG: dd_select_warp:'+where); 
	if (where=='mm_flipped')
		dd_warp(where,1);
	else
		dd_warp(where,5);
}

function dd_str_replace(needle,replacement,haystack)
{
	myregexp = new RegExp(needle,'gi');
	return haystack.replace(myregexp,replacement);
}

/*
function debug_images()
{
	numimg=document.images.length;
	debugstr = 'DEBUG: ' + numimg + ' images: ';
	for (var loopa=numimg-20; loopa<numimg; loopa++) // last twenty
	{
		debugstr = debugstr + ' ' + loopa + ':' + document.images[loopa].src.substring(50,999);
	}
	alert(debugstr);
}
*/

function elapsed_seconds(date1,date2)
{
	return (end - start) / 1000;
}

function dd_destroy_idle_players()
{
	var nowstamp = new Date();
	nowstamp.getTime();
	
	//alert('dd_destroy_idle_players now = ' + nowstamp);
	
	for (var loopav=1; loopav < dd_people_count+1; loopav++)
	{
		aplayer = dd_people[loopav];

		if ((aplayer) && (aplayer!=Player0) && (aplayer!=Player1) && (aplayer.timestamp) && (aplayer.playername!='') && (aplayer.playeremail!='') && (aplayer.playername!=playername))
		{
			idlefor = (nowstamp - aplayer.timestamp);
			if (idlefor > max_idle_time)
			{
				if (dd_v2_debug) alert('*IDLE* [' + aplayer.playername + ']\ntimestamp = ' + aplayer.timestamp + '\n['+idlefor / 1000 / 60+'] is more than ' + max_idle_time / 1000 / 60 + ' minutes old as of\n' + nowstamp);
				dd_destroy_bot(aplayer);
			}
			else
			{
				//alert('Active [' + aplayer.playername + ']\ntimestamp = ' + aplayer.timestamp + '\n['+idlefor / 1000 / 60+'] is less than ' + max_idle_time / 1000 / 60 + ' minutes old as of\n' + nowstamp);
			}
		}
				
	}
	
	setTimeout('dd_destroy_idle_players()',check_idle_time);
}

function submitViaEnter(evt) 
{
	evt = (evt) ? evt : event;
	var target = (evt.target) ? evt.target : evt.srcElement;
	var form = target.form;
	var charCode = (evt.charCode) ? evt.charCode :
	((evt.which) ? evt.which : evt.keyCode);
	if ((charCode == 13) || (charCode == 3)) 
	{
		document.chatform.mychat.focus();
		if (playeremail=='guest') 
		{ 
			if (confirm('You are using the GUEST account. \nYour temporary name is '+playername+'.\nYou must sign up to chat with other users.\n[OK] = Register NOW\n[CANCEL] = Keep playing as a guest'))
			{
				parent.location.href='http://www.digitaldeadwood.com/register.html';

			} 
			
			return false;
		}
		if (document.chatform.mychat.value != 'Type here and press ENTER')
		{
			var finalchat = new String();
			finalchat = document.chatform.mychat.value;
			if (finalchat.indexOf('#')!=-1)
			{
				//if (dd_v2_debug) alert('DEBUG: You typed a pound character: ' + finalchat);
				//finalchat = finalchat.replace(/\#/,'&pound;');
				finalchat = finalchat.replace(/\#/,'!pound!'); // special
				//if (dd_v2_debug) alert('DEBUG: I fixed the pound character: ' + finalchat);
			}
			more_chat_please(finalchat,uid,Player1.getLeft(),Player1.getTop(),map,Player1.playername,Player1.look,playeremail);
			document.chatform.mychat.select();
			document.chatform.mychat.focus();
			//dd_chatter(document.chatform.mychat.value,0,0,1); // instantly visible? 
		}
    		return false;
	}
	return true;
}

function more_chat_please(amessage,uid,cx,cy,map,myname,mylook,myemail) 
{	
	if (!dd_loaded) return;
	if ((map=='000_shoot') || (map=='gem_shootout1_flipped')) return; // no shootout chatter
	submiturl = 'dd_chat.php?m='+map+'&l='+most_recent_anumba+'&z='+Math.random()+'&x='+cx+'&y='+cy+'&uid='+uid+'&n='+myname+'&a='+mylook+'&e='+myemail;
	if (amessage) submiturl = submiturl +'&c='+amessage; 
	if (ddiframe) ddiframe.location.href=submiturl;
}


function dd_drag_window(thiswin)
{
	if (!thiswin) return;
	//if (is.mac) return;
	
	if (dd_dragging)
	{
		dd_dragging = false;
		return;
	}

	dd_dragging=thiswin;
	dd_dragging.dragYoffset = -32;
	dd_dragging.dragXoffset = -dd_dragging.width / 2;
	dd_dragging.wasdragged = true;

}


var just_arrived = true;
var position_update_count = 0;
function listen_to_chats()
{
	if (!dd_loaded) return;
	if ((map=='000_shoot') || (map=='gem_shootout1_flipped')) return; // no shootout chatter
	
	if (dd_chat_on)
	{
		ppx = Player1.getLeft();
		ppy = Player1.getTop();

		position_update_count++;
		if (position_update_count > 2) position_update_count = 1; 	// loop every 3x
		if (position_update_count == 1) 				// time to update?
		{
			if (just_arrived) // say hello
			{
				//if (dd_v2_debug) alert('DEBUG: I just arrived.  Teleporting ['+Player1.playername+'] to '+ppx+','+ppy+'.');
				more_chat_please('_!_',uid,ppx,ppy,map,Player1.playername,Player1.look,playeremail);//Player1.playeremail);
				just_arrived = false;
			}
			else // update pos
			{
				more_chat_please('_',uid,ppx,ppy,map,Player1.playername,Player1.look,playeremail);//Player1.playeremail);
			}
			
		}
		else	// silently ask for new chats
			more_chat_please(0  ,uid,ppx,ppy,map,Player1.playername,Player1.look,playeremail);//Player1.playeremail);
		
		setTimeout('listen_to_chats()',9000+(1000*Math.random())); // 10000 = 10 seconds, so this is 8-10 secs
		
	}
}

function dd_mute_chat(dontsave)
{

	if (!dontsave) dd_chat_on = (!dd_chat_on); // toggle

	//alert('DEBUG: dd_mute_chat dd_chat_on='+dd_chat_on);
	//if (!document.configform) alert('missing form!');
	//if (!document.configform.mutechat) alert('missing mute!');

	if (dd_chat_on)
	{
		//alert('turning chat on!');
		//alert(document.configform.mutechat.checked);
		document.configform.mutechat.checked=true;
		//alert(document.configform.mutechat.checked);
			
		//ddiframe.location.href='dd_chat.php';
		if (dd_loaded) listen_to_chats();

		if ((playeremail != 'guest') && (!dontsave)) // SAVE to user DB
			dd_submit_pixel('dd_pixel.php?cmd=mute_chat&val=0&rand='+Math.random()+'&uid='+uid);
			
	}
	else
	{
		//ddiframe.location.href='mute/'; // the code there checks parent.dd_chat_on

		//alert('turning chat off!');
		document.configform.mutechat.checked=false;

		if ((playeremail != 'guest') && (!dontsave)) // SAVE to user DB
			dd_submit_pixel('dd_pixel.php?cmd=mute_chat&val=1&rand='+Math.random()+'&uid='+uid);

	}

}

function dd_mute_music(dontsave)
{
	//alert('DEBUG: dd_mute_music - dd_music_on=' + dd_music_on);
	//if (!document.configform) alert('missing form!');
	//if (!document.configform.mutemusic) alert('missing mute!');

	if (!dontsave) dd_music_on = !dd_music_on; // toggle

	//alert('DEBUG: dd_mute_music NOW dd_music_on=' + dd_music_on);

	if (parent.ddmusicframe)
	{
		//if (string_contains(parent.ddmusicframe.location.href,'mute'))
		if (dd_music_on)
		{
			document.configform.mutemusic.checked=true;

			if (string_contains(parent.ddmusicframe.location.href,'mute'))
				parent.ddmusicframe.location.href='music/'; // start MP3 streaming
			//alert('DEBUG: dd_mute_music: music is now ON');
			if ((playeremail != 'guest') && (!dontsave)) // SAVE to user DB
				result_img = dd_submit_pixel('dd_pixel.php?cmd=mute_music&val=0&rand='+Math.random()+'&uid='+uid);


		}
		else
		{
			document.configform.mutemusic.checked=false;

			//if (string_contains(parent.ddmusicframe.location.href,'music'))
				parent.ddmusicframe.location.href='mute/'; // empty html
			//alert('DEBUG: dd_mute_music: music is now OFF');
			if ((playeremail != 'guest') && (!dontsave)) // SAVE to user DB
				result_img = dd_submit_pixel('dd_pixel.php?cmd=mute_music&val=1&rand='+Math.random()+'&uid='+uid);
				
		}
	}
	//else
	//	alert('DEBUG: missing music frame!');
	
}

function dd_random_int(maxval)
{
	return Math.floor(Math.random()*maxval);
}

function dd_open_window(whichone) // toggles open/close
{
	if (!whichone) return;

	if (dd_v2_debug) dd_debugme('dd_open_window id='+whichone.id+' visible='+whichone.visible);

	dd_ignore_next_click = true; // dont walk for GUI events
	dd_dragging = false; // reset drag state
	
	if (whichone.visible) 
	{
		//whichone.moveTo(800,600);
		whichone.visible=false;
		whichone.hide(); 
		whichone.last_top = whichone.getTop();
		whichone.last_left = whichone.getLeft();
		whichone.moveTo(0,-1000);
	}
	else
	{	// slide up
		whichone.visible=true;
		whichone.show();
		if (whichone == window_shootout)
		{
			whichone.moveTo(24,35);
		}
		else if (!whichone.wasdragged) // startup position
		{
			whichone.moveTo(384-whichone.width / 2, 35 + (222-whichone.height / 2));
			whichone.last_top = whichone.getTop();
			whichone.last_left = whichone.getLeft();
		}
		else
		{
			whichone.moveTo(whichone.last_left, whichone.last_top);
		}
			
	}
	
	// tell the game not not respond to clicks if a window is open
	notbusy = (!(
			(window_history && window_history.visible) || 
			(window_inventory && window_inventory.visible) || 
			(window_journal && window_journal.visible) || 
			(window_slots && window_slots.visible) || 
			(window_map && window_map.visible) || 
			(window_blackjack && window_blackjack.visible)
		)); // window_shootout etc..?
	no_warping = (window_slots.visible || window_blackjack.visible); // || window_shootout.visible);
}

function dd_force_open_window(whichone) // only open
{
	if (!whichone) return;

	dd_ignore_next_click = true; // dont walk for GUI events
	dd_dragging = false; // reset drag state
	
	if (!whichone.visible) 
	{	// slide up
		whichone.visible=true;
		whichone.show();
		if (whichone == window_shootout)
		{
			whichone.moveTo(24,35);
		}
		else if (!whichone.wasdragged) // startup position
		{
			whichone.moveTo(384-whichone.width / 2, 35 + (222-whichone.height / 2));
			whichone.last_top = whichone.getTop();
			whichone.last_left = whichone.getLeft();
		}
		else
		{
			whichone.moveTo(whichone.last_left, whichone.last_top);
		}
			
	}
	
	// tell the game not not respond to clicks if a window is open
	notbusy = (!(
			(window_history && window_history.visible) || 
			(window_inventory && window_inventory.visible) || 
			(window_journal && window_journal.visible) || 
			(window_slots && window_slots.visible) || 
			(window_map && window_map.visible) || 
			(window_blackjack && window_blackjack.visible)
		)); // window_shootout etc..?
	no_warping = (window_slots.visible || window_blackjack.visible); // || window_shootout.visible);
}

function dd_close_window(whichone) // only close
{
	if (!whichone) return;

	dd_ignore_next_click = true; // dont walk for GUI events
	dd_dragging = false; // reset drag state
	
	if (whichone.visible) 
	{
		//whichone.moveTo(800,600);
		whichone.visible=false;
		whichone.hide(); 
		whichone.last_top = whichone.getTop();
		whichone.last_left = whichone.getLeft();
		whichone.moveTo(0,-1000);
	}
	
	// tell the game not not respond to clicks if a window is open
	notbusy = (!(
			(window_history && window_history.visible) || 
			(window_inventory && window_inventory.visible) || 
			(window_journal && window_journal.visible) || 
			(window_slots && window_slots.visible) || 
			(window_map && window_map.visible) || 
			(window_blackjack && window_blackjack.visible)
		)); // window_shootout etc..?
	no_warping = (window_slots.visible || window_blackjack.visible); // || window_shootout.visible);
}

function dd_history_link(linkname)
{
	if (!linkname) return;
	
	if (!notbusy) return; // gui windows open?
	
	dd_open_window(window_history);
	
	theurl = 'history/?section=' + linkname;
	
	//alert('DEBUG: dd_history_link: ' + linkname);
	
	if (historyframe) historyframe.location.href = theurl;
	//else alert('Missing historyframe!');

}


function dd_pixel_onload()
{
	if (dd_v2_debug) alert('DEBUG: [' + this.dd_event_name + '] \n SUCCESS - This means the server got the data and SAVED it to the database. \n src='+this.src+' w='+this.width+' h='+this.height);
	this.bLoaded=true;
}
function dd_pixel_onerror()
{
	if (dd_v2_debug) alert('DEBUG: [' + this.dd_event_name + '] ERROR src='+this.src+' w='+this.width+' h='+this.height);
}
function dd_pixel_onabort()
{
	if (dd_v2_debug) alert('DEBUG: [' + this.dd_event_name + '] ABORT src='+this.src+' w='+this.width+' h='+this.height);
}
function dd_submit_pixel(theimgurl)
{
	if (playeremail=='guest') return false; // guest never saves winnings!

	if (dd_v2_debug) alert('dd_submit_pixel DEBUG:\n'+theimgurl);
	
	oImage = new Image();
	oImage.onload = dd_pixel_onload;
	oImage.onerror = dd_pixel_onerror;
	oImage.onabort = dd_pixel_onabort;
	oImage.bLoaded = false;
	oImage.dd_event_name = 'DDpixel:' + theimgurl;
	oImage.src = theimgurl;
	return oImage;
}

function bux(n) // Format the given number as a dollar amount for display.
{   
  if (!n) n = 0.0;
  var a, b;
  a = Math.abs(n);
  b = 100 * (a - Math.floor(a));
  if (b < 10)
    b = "0" + b;
  return (n < 0 ? "-" : "" ) + "$" + Math.floor(a) + "." + b;
}


function dd_done_slots(quarters)
{
	
	dd_close_window(window_slots); // close it

	if (playeremail=='guest') return false; // guest never saves winnings!

	//alert('DEBUG: Done slots!  You now have ' + quarters + ' quarters so your ' + dd_user_dollars + ' became  ' + (quarters * 0.25));
	dd_user_dollars = (quarters * 0.25);	// quarters
	
	if (document.journalform.dollars) document.journalform.dollars.value = bux(dd_user_dollars);
	
	// write it to the user database using a quick img download NOW!
	// this function is called from the slots window, in a higher dir
	theimgurl='../dd_pixel.php?&uid='+uid+'&cmd=dollars&val='+dd_user_dollars+'&rand='+Math.random();
	result_img = dd_submit_pixel(theimgurl);
	
}

function dd_slots(anumber)
{
	if (!dd_loaded) return;
	if (!anumber) anumber = '';

	if (window_blackjack.visible) return;

	//alert('DEBUG: Slots!');
	if (!window_slots) return; //{ alert('DEBUG: Slots is missing!'); return; }
	if (!slotsframe) return; //{ alert('DEBUG: Slotsframe is missing!'); return; }
	//if (!slotsframe.document.slots) { alert('DEBUG: Slots form is missing!'); return; }
	
	dd_user_quarters = Math.round(dd_user_dollars / 0.25);
	if (dd_user_quarters==0) dd_user_quarters=1; // always playable!
	//slotsframe.document.slots.gold.value = dd_user_quarters;
	
	newurl = 'slots'+anumber+'/?rand=' + Math.random();
	if (dd_v2_debug) alert('SLOTS: '+newurl);
	slotsframe.location.href=newurl; // reload

	//if (!window_slots.visible) 
	dd_open_window(window_slots);
}

function dd_done_blackjack(dollars)
{
	
	dd_close_window(window_blackjack); // close it

	if (playeremail=='guest') return false; // guest never saves winnings!

	//alert('DEBUG: Done blackjack!  You now have ' + dollars + ' dollars so your ' + dd_user_dollars + ' became  ' + (dollars));
	dd_user_dollars = dollars;
	
	if (document.journalform.dollars) document.journalform.dollars.value = bux(dd_user_dollars);
	
	// write it to the user database using a quick img download NOW!
	// this function is called from the blackjack window, in a higher dir
	theimgurl='../dd_pixel.php?&uid='+uid+'&cmd=dollars&val='+dd_user_dollars+'&rand='+Math.random();
	result_img = dd_submit_pixel(theimgurl);
	
}

function dd_blackjack(anumber)
{
	if (!dd_loaded) return;
	if (!anumber) anumber = '';

	if (window_slots.visible) return;

	//alert('DEBUG: blackjack!');
	if (!window_blackjack) return; //{ alert('DEBUG: blackjack is missing!'); return; }
	if (!blackjackframe) return; //{ alert('DEBUG: blackjackframe is missing!'); return; }
	//if (!blackjackframe.document.blackjack) { alert('DEBUG: blackjack form is missing!'); return; }
	
	//if (!window_blackjack.visible) 
	//blackjackframe.location.href='http://www.digitaldeadwood.com/test/blackjack/?rand=' + Math.random(); // reload


	newurl = 'blackjack'+anumber+'/?rand=' + Math.random();
	if (dd_v2_debug) alert('BJ: '+newurl);

	blackjackframe.location.href=newurl; // reload
	dd_open_window(window_blackjack);

	//blackjackframe.document.blackjack.dollars.value = dd_user_dollars;
	//blackjackframe.dd_bj_init(dd_user_dollars);
	

}

function grid_to_pixelX(gx,gy)
{
	//if (gy % 2) xofs=24; else xofs=0;
	if (gy % 2) xofs=48; else xofs=24;
	return ((gx * 48) + xofs);// + 8; // $CK tweak pos
}

function grid_to_pixelY(gx,gy)
{
	return ((gy+1) * 12);// - 8; // $CK tweak pos
}

function pixel_to_gridX(px,py)
{
	nudge=10;
	gy = pixel_to_gridY(px,py);
	if (gy % 2) xofs=-nudge; else xofs=nudge-24; // center + nudge
	theanswer = parseInt((px+xofs) / 48);
	if (theanswer > max_grid_X) theanswer = max_grid_X;
	if (theanswer < 0) theanswer = 0;
	return theanswer;
}

function pixel_to_gridY(px,py)
{
	yofs=-1; // nudge due to even lines being 1 too many
	theanswer = parseInt((py+yofs) / 12);
	if (theanswer > max_grid_Y) theanswer = max_grid_Y;
	if (theanswer < 0) theanswer = 0;
	return theanswer;
	
}

function update_gridXY() // selects the map grid space closest to mouse
{
	currentGridX = pixel_to_gridX(currentMouseX,currentMouseY);
	currentGridY = pixel_to_gridY(currentMouseX,currentMouseY);
	
	if (currentGridY > lowest_clickable_grid_row) return; // ignore offscreen

	//if (document.dd_form.gx)   document.dd_form.gx.value = currentGridX;
	//if (document.dd_form.gy)   document.dd_form.gy.value = currentGridY;
	//if (document.dd_form.gIMG) document.dd_form.gIMG.value = dd_img[currentGridY][currentGridX]; // debug?

	//highlight grid 
	if (gcursor) gcursor.moveTo(grid_to_pixelX(currentGridX,currentGridY)-24,grid_to_pixelY(currentGridX,currentGridY)-12-1);

	//follow mouse - small version for xcursor.gif
	//if (xcursor) xcursor.moveTo(currentMouseX - 24,currentMouseY - 12);
	if (xcursor) xcursor.moveTo(currentMouseX - 36,currentMouseY - 36);
	
	//SLIDE GRID SPAMMY
	// if (xcursor) xcursor.slideTo(grid_to_pixelX(currentGridX,currentGridY),grid_to_pixelY(currentGridX,currentGridY)); else alert('xcursor is gone!');
	
	// BIG YUKKY DEBUG
	if (dd_v2_debug)
	{
	ddgx = pixel_to_gridX(currentMouseX,currentMouseY);
	ddgy = pixel_to_gridY(currentMouseX,currentMouseY);
	ddpx= grid_to_pixelX(ddgx,ddgy);
	ddpy= grid_to_pixelY(ddgx,ddgy);
	ddggx = pixel_to_gridX(ddpx,ddpy);
	ddggy = pixel_to_gridY(ddpx,ddpy);
	dd_debugme('m='+currentMouseX+','+currentMouseY+' g='+ddgx+','+ddgy+' p='+ddpx+','+ddpy+' g='+ddggx+','+ddggy+' '+dd_img[currentGridY][currentGridX]);
	}

}

function dd_name_to_num(myname)
{
	if (!myname) return 1;
	
	//alert('DEBUG: dd_name_to_num ' + myname);

	for (var loopav=1; loopav < dd_people_count+1; loopav++)
	{
		if (dd_people[loopav])
		{
			if (string_contains(dd_people[loopav].playername,myname))
			{
				foundit = true;

				//alert('DEBUG: dd_name_to_num ' + myname + ' found num=' + loopav);

				return loopav;
			}
		}
	}
	//alert('DEBUG: dd_name_to_num could not find ' + myname);
	return 1;
}

var bubbles = 0;
function dd_chatter(msg,x,y,personNUMBER,personNAME,personLOOK,personIP,personEMAIL)
{
	//alert('DEBUG: dd_chatter: msg='+msg+', x='+x+', y='+y+', num='+personNUMBER+', name='+personNAME+', look='+personLOOK+', ip='+personIP);
	
	var bubblefade = 20000; // 15000 = 15 sec

	if (!dd_loaded) return;
	if (!dd_chat_on && (personNUMBER != NPCSLOT)) return; //2) return; // always let bots speak

	if (!personNUMBER) personNUMBER = dd_name_to_num(personNAME); // sanity
	if (!personNUMBER) 
	{
		if (dd_v2_debug) alert('DEBUG: No personNUMBER: assuming 1...');
		personNUMBER = 1; // sanity
	}

	thisperson = dd_people[personNUMBER];
	if (!x) x = thisperson.getLeft();// + thisperson.getWidth();
	if (!y) y = thisperson.getTop();
	
	if ((personNAME) && (personNAME != Player1.playername) && (personNUMBER!=NPCSLOT)) // update a chat client // (personNUMBER > 2) &&
	{
		//alert('DEBUG: got a non-me NAME: attempting respawn!');
		fx = x + thisperson.getWidth() / 2; // foot position 
		fy = y + thisperson.getHeight() - 16; // foot position in 3d middle
		gx = pixel_to_gridX(fx,fy);
		gy = pixel_to_gridY(fx,fy);
		delme = (msg == '-'); // delete me
		telme = (msg == '_!_'); // teleport me
		//if (dd_v2_debug) { if (telme) alert('DEBUG['+playername+']: Just got a TEL message from ['+personNAME+'].'); }
		dd_respawn(personNAME,personLOOK,gx,gy,personIP,personEMAIL,delme,telme);
	}

	//if (!thisperson) return; 

	if ((msg) && (msg != '_') && (msg != '_!_') && (msg != '-'))
	{

		// add name on top
		if (personNAME) msg = '<font color=#888888><center>'+personNAME+'</center></font> ' + msg; // short msgs have room for name

		if (msg.length > 100)
			bubblefade = 60000; // LOOONG messages

		if (personNUMBER==NPCSLOT) // (personNUMBER==2) // NPC hardcoded!
		{
			if (personEMAIL=='silverado_NPC')
				bubblefade=6000; // silverado girl
			else
				bubblefade=0; // all other NPCs the bubble never fades
			
			bubble=0; // not 99 NPC big bubble
		}
		else
		{
			bubble=personNUMBER;
		}


		if (bubble==0) // NPC - bubble_npc.gif
		{
			msg = '<div class=bubdivNPCINSIDE>' + msg + '</div>'; // chat padding
			y -= 64; // higher up
		}
		else
		{
			msg = '<div class=bubdivINSIDE>' + msg + '</div>'; // chat padding
		}

		//alert('DEBUG: HTML chatter to bubble '+bubble);
		y -= 72; //80;
		if (bubble==0) { bub0.ele.innerHTML=msg; bub0.show(); bub0.moveTo(x,y); if (bubblefade) setTimeout('bub0.hide()',bubblefade);  }
		if (bubble==1) { bub1.ele.innerHTML=msg; bub1.show(); bub1.moveTo(x,y); if (bubblefade) setTimeout('bub1.hide()',bubblefade);  }
		if (bubble==2) { bub2.ele.innerHTML=msg; bub2.show(); bub2.moveTo(x,y); if (bubblefade) setTimeout('bub2.hide()',bubblefade);  }
		if (bubble==3) { bub3.ele.innerHTML=msg; bub3.show(); bub3.moveTo(x,y); if (bubblefade) setTimeout('bub3.hide()',bubblefade);  }
		if (bubble==4) { bub4.ele.innerHTML=msg; bub4.show(); bub4.moveTo(x,y); if (bubblefade) setTimeout('bub4.hide()',bubblefade);  }
		if (bubble==5) { bub5.ele.innerHTML=msg; bub5.show(); bub5.moveTo(x,y); if (bubblefade) setTimeout('bub5.hide()',bubblefade);  }
		if (bubble==6) { bub6.ele.innerHTML=msg; bub6.show(); bub6.moveTo(x,y); if (bubblefade) setTimeout('bub6.hide()',bubblefade);  }
		if (bubble==7) { bub7.ele.innerHTML=msg; bub7.show(); bub7.moveTo(x,y); if (bubblefade) setTimeout('bub7.hide()',bubblefade);  }
		if (bubble==8) { bub8.ele.innerHTML=msg; bub8.show(); bub8.moveTo(x,y); if (bubblefade) setTimeout('bub8.hide()',bubblefade);  }
		if (bubble==9) { bub9.ele.innerHTML=msg; bub9.show(); bub9.moveTo(x,y); if (bubblefade) setTimeout('bub9.hide()',bubblefade);  }
		if (bubble==10) { bub10.ele.innerHTML=msg; bub10.show(); bub10.moveTo(x,y); if (bubblefade) setTimeout('bub10.hide()',bubblefade);  }
		if (bubble==11) { bub11.ele.innerHTML=msg; bub11.show(); bub11.moveTo(x,y); if (bubblefade) setTimeout('bub11.hide()',bubblefade);  }
		if (bubble==12) { bub12.ele.innerHTML=msg; bub12.show(); bub12.moveTo(x,y); if (bubblefade) setTimeout('bub12.hide()',bubblefade);  }
		if (bubble==13) { bub13.ele.innerHTML=msg; bub13.show(); bub13.moveTo(x,y); if (bubblefade) setTimeout('bub13.hide()',bubblefade);  }
		if (bubble==14) { bub14.ele.innerHTML=msg; bub14.show(); bub14.moveTo(x,y); if (bubblefade) setTimeout('bub14.hide()',bubblefade);  }
		if (bubble==15) { bub15.ele.innerHTML=msg; bub15.show(); bub15.moveTo(x,y); if (bubblefade) setTimeout('bub15.hide()',bubblefade);  }
		if (bubble==16) { bub16.ele.innerHTML=msg; bub16.show(); bub16.moveTo(x,y); if (bubblefade) setTimeout('bub16.hide()',bubblefade);  }
		if (bubble==17) { bub17.ele.innerHTML=msg; bub17.show(); bub17.moveTo(x,y); if (bubblefade) setTimeout('bub17.hide()',bubblefade);  }
		if (bubble==18) { bub18.ele.innerHTML=msg; bub18.show(); bub18.moveTo(x,y); if (bubblefade) setTimeout('bub18.hide()',bubblefade);  }
		if (bubble==19) { bub19.ele.innerHTML=msg; bub19.show(); bub19.moveTo(x,y); if (bubblefade) setTimeout('bub19.hide()',bubblefade);  }
		if (bubble==20) { bub20.ele.innerHTML=msg; bub20.show(); bub20.moveTo(x,y); if (bubblefade) setTimeout('bub20.hide()',bubblefade);  }
	}
	//alert('Chatter: ' + msg + ' x=' + x + ' y=' + y);
	return false; // never submit form
}

function dd_can_stand(gx,gy)
{	// return true if sea level (alt=0)
	return (dd_alt[gy]) && (!dd_alt[gy][gx])
}

function dd_debugme(thisstr)
{
	if (!dd_v2_debug) return;
	if (document.chatform) 
		document.chatform.mychat.value=thisstr;
}

function shootout_reward()
{
	if (dd_v2_debug) dd_debugme('Shootout reward: '+bux(shootout_score));
	if (shootout_score < 1) return;
	//player_legendstatus = "Gunslinger";
	//dd_refresh_legendstatus('<font color=red>'+player_legendstatus+'</font>');
	//setTimeout('dd_open_window(window_journal);',3000); // show the update
	//newsubmit = 'dd_pixel.php?cmd2=legendstatus&val2='+player_legendstatus+'&cmd=inventory&val='+player_inventory+'&rand='+Math.random()+'&uid='+uid;
	dd_user_dollars = dd_user_dollars + shootout_score;
	if (document.journalform.dollars) document.journalform.dollars.value = bux(dd_user_dollars);
	// write it to the user database using a quick img download NOW!
	theimgurl='dd_pixel.php?&uid='+uid+'&cmd=dollars&val='+dd_user_dollars+'&rand='+Math.random();
	dd_submit_pixel(theimgurl);
}
function shootout_begin()
{
	//if (dd_v2_debug) alert('DEBUG: shootout_begin()');
	if (dd_v2_debug) dd_debugme('Shootout has begun!');
	
	//shootout_level = 1; // already set
	shootout_score = 0;
	shootout_hits = 0;
	shootout_misses = 0;
	shootout_bullets = 24;
	//shootout_time = 60; // already set
	shootout_paused=false;

	dd_update_shootout_window();
	
	numbadguys = dd_people_shootout.length;
	if (!numbadguys) alert('ERROR: No badguys!');

	for (var bgloop=1; bgloop<numbadguys+1; bgloop++)
	{
		if (dd_people_shootout[bgloop])
		{
			dd_people_shootout[bgloop].dead = false;
			dd_people_shootout[bgloop].shootable = true;
			dd_people_shootout[bgloop].ele.src = shootout_cover_img;
			dd_people_shootout[bgloop].idleframes = 0;
		}
	}

	if (first_shootout_frame)
	{
		setTimeout('shootout_timer()',1000); // the clock
		shootout_ai(); // the bots
		first_shootout_frame = false;
	}
}
function shootout_ai() // bobbleheads
{
	if (dd_v2_debug) if (document.chatform) document.chatform.mychat.value='DEBUG: shootout AI';

	maxidleframes = 5;
	
	shootout_ai_frequency = 600 - (50*(shootout_level)); // 1 to 10
	shootout_ai_rand_time = 500; //1000-(shootout_level*100); 

	if (!dd_people_shootout) alert('ERROR: No shootout people!');
	numbadguys = dd_people_shootout.length;
	if (!numbadguys) alert('ERROR: No badguys!');
	
	if (!shootout_paused)
	{
	for (var bgloop=1; bgloop<numbadguys+1; bgloop++)
	{
		if (dd_people_shootout[bgloop])
		{
			if (!dd_people_shootout[bgloop].dead)
			{
				dd_people_shootout[bgloop].idleframes++;
				var rr = Math.random();
				if (rr > 0.9)
				{
					if (!dd_people_shootout[bgloop].shootable)
					{	// aim
						dd_people_shootout[bgloop].shootable = true;
						dd_people_shootout[bgloop].ele.src = shootout_open_img;
						dd_people_shootout[bgloop].idleframes = 0;
					}
					else
					{	// fire!
						dd_people_shootout[bgloop].shootable = true;
						dd_people_shootout[bgloop].ele.src = shootout_fire_img;
						//dd_sound(myBang);
						sfxbang();
						dd_people_shootout[bgloop].idleframes = 999; // quickly sit back down
					}
				}
				else if ((rr > 0.5) || (dd_people_shootout[bgloop].idleframes > maxidleframes)) // sit back down % of the time
				{
					// stay however you were
					dd_people_shootout[bgloop].shootable = false;
					if (dd_people_shootout[bgloop].ele.src != shootout_cover_img) // avoid flicker
						dd_people_shootout[bgloop].ele.src = shootout_cover_img;
					dd_people_shootout[bgloop].idleframes = 0;
				}
			} // if alive		
		} // if obj exists
	} // for
	} // if
	
	setTimeout('shootout_ai()',shootout_ai_frequency + ((Math.random()-0.5)*shootout_ai_rand_time));
	
}
function shootout_timer()
{
	if (dd_v2_debug) if (document.chatform) document.chatform.mychat.value='DEBUG: shootout_timer ' + shootout_time;

	if (!shootout_paused)
	{
		shootout_time--;
		if (shootout_time > -1)
		{
			if (shootout_time_div) shootout_time_div.innerHTML = shootout_time
		}
		//else
		//	alert('G-A-M-E --- O-V-E-R\nYou have run out of time.');
		else
		{
			sfxreload();
			shootout_paused=true;
			dd_replace_html('shootoutgameoverID','Good try, but you ran out of time.<br>You need to be quicker on the draw.');
			dd_force_open_window(window_shootout_gameover);
			shootout_time = 60; // reset due to game over!
			shootout_level = 1;
		}
	}
	setTimeout('shootout_timer()',1000);
	
}
function dd_update_shootout_window()
{	// avoid flicker by checking if it changed

	// first frame?
	if (!shootout_level_div) shootout_level_div = document.getElementById('shootout_level');
	if (!shootout_score_div) shootout_score_div = document.getElementById('shootout_score');
	if (!shootout_hits_div) shootout_hits_div = document.getElementById('shootout_hits');
	if (!shootout_miss_div) shootout_miss_div = document.getElementById('shootout_miss');
	if (!shootout_bull_div) shootout_bull_div = document.getElementById('shootout_bull');
	if (!shootout_time_div) shootout_time_div = document.getElementById('shootout_time');

	shootout_badguy_score = 10 * shootout_level; // 10 20 30 40 50
	shootout_goodguy_score = 0;
	shootout_score = (shootout_hits * shootout_badguy_score) - (shootout_misses * shootout_goodguy_score);

	// need to update?
	if (shootout_level   != shootout_level_prev)   { shootout_level_prev = shootout_level;     if (shootout_level_div) shootout_level_div.innerHTML = shootout_level; }
	if (shootout_score   != shootout_score_prev)   { shootout_score_prev = shootout_score;     if (shootout_score_div) shootout_score_div.innerHTML = shootout_score; }
	if (shootout_hits    != shootout_hits_prev)    { shootout_hits_prev = shootout_hits;       if (shootout_hits_div)  shootout_hits_div.innerHTML  = shootout_hits; }
	if (shootout_misses  != shootout_misses_prev)  { shootout_misses_prev = shootout_misses;   if (shootout_miss_div)  shootout_miss_div.innerHTML  = shootout_misses; }
	if (shootout_bullets != shootout_bullets_prev) { shootout_bullets_prev = shootout_bullets; if (shootout_bull_div)  shootout_bull_div.innerHTML  = shootout_bullets; }
	if (shootout_time    != shootout_time_prev)    { shootout_time_prev = shootout_time;       if (shootout_time_div)  shootout_time_div.innerHTML  = shootout_time }
}
function shootout_init_level()
{
	//if (dd_v2_debug) alert('DEBUG: shootout_init_level');	
	shootout_score = shootout_hits = shootout_misses = 0;
	shootout_bullets = 24;
	shootout_time=60-(15*(shootout_level-1)); // 60 45 30 15
	if (shootout_time < 5) shootout_time = 5; // secs min
}
function dd_shootme(thisnum) // onclick the targets
{
	// redun!
	shootout_hit_img = 'cache.php?img=walk_redbadguy_dr_hit.gif';
	shootout_dead_img = 'cache.php?img=walk_redbadguy_dr_dead.gif';

	if (shootout_paused) return; // paused: no shooting

	tryme = dd_people_shootout[thisnum];
	if (!tryme)
	{
		dd_debugme('ERROR: Nobody was there to shoot: ' + thisnum);
		return;
	}
	if (tryme.shootable)
	{
		//setTimeout('dd_sound(myOh);',250);
		setTimeout('sfxgotme();',500);
		shootout_hits++;
		shootout_misses--; // not a miss
		tryme.shootable = false;
		tryme.dead = true;
		tryme.ele.src = shootout_dead_img;
		if (dd_v2_debug) dd_debugme('You hit badguy ' + thisnum);
		
		dd_update_shootout_window(); // for newest score
		
		//numbadguys = dd_people_shootout.length;
		//if (!numbadguys) alert('ERROR: No badguys!');
		//bgcount = numbadguys-1;
		bgcount=7; // hardcoded!
	
		if (shootout_hits >= bgcount) // FIXME
		{
			//alert('GAME OVER \nYou got all '+bgcount+' badguys! \nLevel '+ shootout_level + ' completed!');
			buxbux = bux(shootout_score);
			sfxreload();
			shootout_level++;
			shootout_paused=true;
			shootout_reward(); // give bux
			shootout_init_level(); // reset score, time, etc.
			dd_replace_img('shootoutlevelimg','cache.php?img=alertbox_'+shootout_level+'.gif');
			dd_replace_html('shootoutreadyID','Nice shooting! <font color=yellow>REWARD: '+buxbux+'</font> <br> Now try to do it in '+ shootout_time + ' seconds!');
			dd_open_window(window_shootout_ready);
		}
	}
	else
	{
		//setTimeout('dd_sound(myRic);',250);
		setTimeout('sfxricco();',500);
		if (dd_v2_debug) dd_debugme('You missed badguy  ' + thisnum);
	}
}
function dd_fire_away()
{
	if (shootout_bullets < 1) return;
	if (shootout_paused) return;
	
	if (dd_v2_debug) dd_debugme('dd_fire_away xy='+currentMouseX+','+currentMouseY);

	shootout_bullets--;
	shootout_misses++; 

	// cycle thru avail holletholes
	bulletholes++;	if (bulletholes > maxbulletholes) bulletholes = 1;
	bh = bullethole[bulletholes];
	if (!bh)
	{
		if (dd_v2_debug) alert('bullet hole missing: '+bulletholes);
		return;
	}

	//if (dd_v2_debug) alert('dd_fire_away xy='+currentMouseX+','+currentMouseY);
	bh.moveTo(currentMouseX-4,currentMouseY-4);
	bh.show(); 
	
	sfxbang();

	dd_update_shootout_window();

	if (shootout_bullets<1)
	{
		//alert('G-A-M-E --- O-V-E-R\nYou have run out of bullets.'); return;
		if (dd_v2_debug) dd_debugme('You ran out of bullets.');
		sfxreload();
		shootout_paused=true;
		dd_replace_html('shootoutgameoverID','You ran out of bullets.<br>Aim more patiently next time.');
		dd_force_open_window(window_shootout_gameover);
		shootout_time = 60;
		shootout_level = 1;
		return;
	}

}

function dd_click()
{	
	if (!notbusy) return; // windows are open - dont move
	if (document.chatform) document.chatform.mychat.focus();

	giveupcount = 20; // max squares to travel FIXME: this stops the infinite loop!

	if (currentGridY > lowest_clickable_grid_row) return; // on button bar?

	if (currentMouseY > (getClientHeight() - 106)) return; // on top of button bar?

	//if (dd_blocked(currentGridX,currentGridY)) return; // can't click inside a wall!
	
	if (xcursor) // shootout
	{
		dd_fire_away();
		return; // stay put
	}

	// start walking
	// only start if space if blank?
	// if (dd_can_stand(currentGridX,currentGridY)) // empty space?
		dd_start_walking_towards(1,currentGridX,currentGridY,giveupcount); // COMMAND Player1 (dd_people[1])
}


function dd_start_walking_towards(personNUMBER,thisgridx,thisgridy,maxloops)
{
	thisperson = dd_people[personNUMBER];
	if (!thisperson) return;
	if (thisperson.timestamp) thisperson.timestamp.getTime(); // not idle now
	thisperson.dd_walk_target_gx = thisgridx;
	thisperson.dd_walk_target_gy = thisgridy;
	if (!thisperson.dd_currently_walking)
		dd_walk_towards(personNUMBER,maxloops);
}

function dd_alt_check(fromgx,fromgy,togx,togy) // returns altitude difference
{
	current_altitude=0;
	target_altitude=0;
	if (dd_alt[fromgy])
		current_altitude = dd_alt[fromgy][fromgx];
	if (dd_alt[togy])
		target_altitude = dd_alt[togy][togx];

	if (current_altitude > 100) // STUCK inside a building!
		return 9999;
	else
		return target_altitude - current_altitude;
}

function dd_blocked(fromgx,fromgy,togx,togy) // returns true/false
{
	max_step_height = 48; // how big an alt diff till we are blocked

	if 	((fromgx < 0) || 
		(togx < 0) ||
		(fromgy < 0) ||
		(togy < 0) ||
		(fromgx > max_grid_X-1) || 
		(togx > max_grid_X-1) ||
		(fromgy > max_grid_Y-1) ||
		(togy > max_grid_Y-1))
		return 1;

	
	// stand on blank space only
	if (dd_img[togy][togx] != '') return 1; // blocked by a prop
	if (dd_img[fromgy][fromgx] != '') return -1; // stuck inside prop

	// on top of something? check altitude.
	alt_diff = dd_alt_check(fromgx,fromgy,togx,togy);

	alt_diff = Math.abs(alt_diff);

	// stuck in a building? always let them out!
	if (alt_diff == 9999)
	{
		return -1; // stuck
	}
	else if (alt_diff > max_step_height)
	{
		return 1; // blocked
	}
	else
	{
		return 0; // not blocked
	}
}

function base_filename_only(apath) // 'cache.php?img=this.gif' returns 'this'
{
	var thefn = false;
	asa = apath.split('='); // fixme: handle / and ?
	toeq = asa[1];

	if (toeq)
	{
		todot = toeq.split('.');
		thefn = todot[0];
	}
	

	if (thefn)
		return thefn;
	else
		return apath;
}

function dd_update_inv_hint(saythis)
{
	//if (dd_v2_debug) alert('DEBUG: dd_update_inv_hint - ' + saythis);

	if (!saythis) return;
	changeme = document.getElementById('invcommands');
	if (changeme)
	{
		changeme.innerHTML = '<b>' + saythis + '</b>';	
	}
	//else alert('ERROR: can not find invcommands!');
}

function dd_refresh_legendstatus(newlegendstatus)
{
	if (!newlegendstatus) return;
	
	if (dd_v2_debug) alert('DEBUG: dd_refresh_legendstatus - newlegendstatus = ' + newlegendstatus);
	
	thediv = document.getElementById('idlegend');
	if (thediv)
		thediv.innerHTML = newlegendstatus;
	
}

function dd_refresh_inventory()
{
	// if (dd_v2_debug) alert('DEBUG: dd_refresh_inventory - player_inventory = ' + player_inventory);

	allinv = player_inventory.split(',');
	//if (allinv.length)//[0]) // empty is still refreshed
	//{
		for (var loopa=1; loopa<9; loopa++)
		{
			theimg = document.getElementById('buttoninv'+loopa);
			if (theimg)
			{
				if (allinv[loopa-1])
				{
					// dd_image_cache since it comes from dd_map.php
					theimg.src = 'dd_image_cache.php?img='+allinv[loopa-1]+'.gif';
					theimg.src_over = 'dd_image_cache.php?img='+allinv[loopa-1]+'_over.gif';
					theimg.src_base = 'dd_image_cache.php?img='+allinv[loopa-1]+'.gif';
					if ( allinv[loopa-1] == 'item_wbgun' )
						theimg.itemname = "Wild Bill Hickok's Gun";
					else
						theimg.itemname = allinv[loopa-1];
					theimg.title='['+theimg.itemname+'] Use this item during a conversation with Wild Bill...';
					theimg.onmouseover=function () { this.src=this.src_over; dd_update_inv_hint(this.itemname); } ;
					theimg.onmouseout=function () { this.src=this.src_base; } ; 
				}
				else
				{
					// cache since it comes from dd.php
					theimg.src = 'cache.php?img=button_inv.gif'; 
					theimg.title='( Empty Inventory Slot ) Find items around town that you can pick up!';
					theimg.onmouseover=function () { this.src='cache.php?img=button_inv_over.gif'; dd_update_inv_hint('( Empty Inventory Slot )'); } ;
					theimg.onmouseout=function () { this.src='cache.php?img=button_inv.gif'; } ;
				}
				
			}
			//else alert('ERROR: could not find buttoninv' + loopa);
		}
	//}
	//else alert('ERROR: no inventory!');
}

function dd_pick_up(anitem,imgid)
{
	anitem = base_filename_only(anitem);
	
	if ((!anitem) || (anitem==undefined) || (anitem=='undefined') || (anitem=='image')) return false;
	
	if (dd_v2_debug) alert('DEBUG: ' + anitem + ' [id=' + imgid + '] was added to your inventory.');
	
	if (player_inventory.length) player_inventory = player_inventory + ',';
	player_inventory = player_inventory + anitem;

	dd_refresh_inventory();

	dd_open_window(window_inventory);
	
	newsubmit = 'dd_pixel.php?cmd=inventory&val='+player_inventory+'&rand='+Math.random()+'&uid='+uid;
	
	if (dd_v2_debug) { if (!confirm('DEBUG: player_inventory=' + player_inventory + ' SUBMIT THIS? \n'+newsubmit)) return; }
	
	dd_submit_pixel(newsubmit);
	
	if (imgid)
	{
		var theimg = new CrossBrowserElement(imgid);
		if (theimg) theimg.hide();
		var thetarget = new CrossBrowserElement(imgid+'_target');
		if (thetarget) thetarget.hide();
	}
}

function string_contains(haystack,needle)
{
	return (haystack.indexOf(needle) > -1);
}

function dd_touch_this(touched)
{
	if (string_contains(touched,'warp'))
	{
		
		//alert('DEBUG WARP: touched='+touched);
		
		toucha = touched.split('='); // door_warp=ws4.gif
		if (toucha[2])
			warptodot = toucha[2]; // two '=' in url
		else
			warptodot = toucha[1];

		//alert('DEBUG WARP: warptodot='+warptodot);

		if (warptodot)
		{
			warpa = warptodot.split('.');
			warpto = warpa[0];

			//alert('DEBUG WARP: warpto='+warpto);

			if (warpto)
			{
				dd_warp(warpto,dirNONE);
				return;
			}
		}
	}
	
	//only triggered by click
	//if (string_contains(touched,'slot_machine'))
	//{
	//	dd_slots();
	//}

	if (string_contains(touched,'item'))
	{
		toucha = touched.split('_'); // item_name.gif
		touchi = toucha[1];
		if (touchi)
		{
			toucha = touchi.split('.');
			itemname = toucha[0];
			if (itemname)
			{
				dd_pick_up(itemname);
			}
		}
	}
	
	/*
	if (string_contains(touched,'prop')
	toucha = touching.split('_');
	propto = toucha[1];
	if (propto)
	{
		alert('Player touched a prop: ' + propto);
		//return;
	}
	*/
}

function dd_walk_away(in_this_corner)
{
	// default direction: off the bottom middle..
	dd_exit_gx = 8;
	dd_exit_gy = lowest_clickable_grid_row;

	// where do we start at? we need the REVERSE of the target corner
	if (in_this_corner == 3)//7) // top left = 1,8
	{
		dd_exit_gx = 1;
		dd_exit_gy = 8;
	}
	else if (in_this_corner == 1)//9) // top right = 14,8
	{
		dd_exit_gx = 14;
		dd_exit_gy = 8;
	}
	else if (in_this_corner == 9)//1) // bottom left = 1,34
	{
		dd_exit_gx = 1;
		dd_exit_gy = lowest_clickable_grid_row;
	}
	else if (in_this_corner == 7)//3) // bottom right = 14,34
	{
		dd_exit_gx = 14;
		dd_exit_gy = lowest_clickable_grid_row;
	}
	else if (in_this_corner == 2)//8)
	{
		dd_exit_gx = 8;
		dd_exit_gy = 1;
	}
	else if (in_this_corner == 4)//6)
	{
		dd_exit_gx = 14;
		dd_exit_gy = 22;
	}
	else if (in_this_corner == 6)//4) left
	{
		dd_exit_gx = 1;
		dd_exit_gy = 22;
	}
	else if (in_this_corner == 8)//2) bottom mid
	{
		dd_exit_gx = 8;
		dd_exit_gy = lowest_clickable_grid_row;;
	}

	walkedgex=grid_to_pixelX(dd_exit_gx,dd_exit_gy);
	walkedgey=grid_to_pixelY(dd_exit_gx,dd_exit_gy);
	
	if (dd_v2_debug) alert('DEBUG['+playername+']: Walking off the edge of the screen: grid='+dd_exit_gx+','+dd_exit_gy+' pix='+walkedgex+','+walkedgey);
	
	// walk off edge of screen for other chat clients: no more ZOMBIEs
	more_chat_please('-',uid,walkedgex,walkedgey,map,Player1.playername,Player1.look,playeremail);
}

function dd_maybe_logout()
{
	if (!dd_loaded) return;

	if (confirm("Are you sure you want to stop playing and log out? \n[OK] = Log out now \n[CANCEL] = Continue playing"))
	{
		dd_walk_away(8);
		theURL = 'http://www.digitaldeadwood.com';
		timeoutJS = 'parent.document.location.href="'+theURL+'";';
		setTimeout(timeoutJS,2000); // warp two seconds later
	}

	return false;
}

function dd_warp(mapname,in_this_corner)
{
	if (!dd_loaded) return;

	if (!mapname) return;
	
	if (no_warping) 
	{
		alert('You have to finish playing and settle \nyour debts before you can go to another map. \nClick [QUIT] on the game window first.');
		return; // not while playing! 
	}
	
	// alert('DEBUG WARP: dd_warp mapname = ' + mapname);

	if (document.chatform) document.chatform.mychat.value='Walking to another location...';

	dd_walk_away(in_this_corner);
	
	if (in_this_corner)
		theURL = 'dd.php?uid='+uid+'&m='+mapname+'&l='+in_this_corner+'&rand='+Math.random();
	else
		theURL = 'dd.php?uid='+uid+'&m='+mapname+'&rand='+Math.random();

	timeoutJS = 'document.location.href="'+theURL+'";';
	
	//if (!confirm('DEBUG: wanna [' + timeoutJS + ']?')) return; // DEBUG don't warp!
	
	setTimeout(timeoutJS,2000); // warp two seconds later
}

function dd_warp_from_historylink(mapname,in_this_corner)
{
	if (!dd_loaded) return;

	if (in_this_corner)
		theURL = '../dd.php?uid='+uid+'&m='+mapname+'&l='+in_this_corner+'&rand='+Math.random();
	else
		theURL = '../dd.php?uid='+uid+'&m='+mapname+'&rand='+Math.random();

	//alert('dd_warp_from_historylink [' + theURL + '] ddtop is ' + parent.ddmid);

	if(mapname) 
	{
		parent.ddmid.document.location.href=theURL;
	}
}

function dd_touch(personNUMBER,nearx,neary)
{
	if (personNUMBER!=1) return; // bots don't trigger things
	
	// touching a screen edge = warp
	//if (neary <= 2) 		{ dd_warp(map_warp_up); } // return; }
	//if (neary >= max_grid_Y-2) 	{ dd_warp(map_warp_dn); } // return; }
	//if (nearx >= max_grid_X-2) 	{ dd_warp(map_warp_rt); } // return; }
	//if (nearx <= 2) 		{ dd_warp(map_warp_lf); } // return; }

	// test any nearby spaces for warps, props, triggers, bots
	for (var gx=nearx-1; gx<nearx+2; gx++)
	{
		for (var gy=neary-1; gy<neary+2; gy++)
		{
			//alert('dd_touching ' + gx + ',' + gy);

			// react to things I'm about to touch
			if (dd_img[gy]) // sanity
			{
				touching=dd_img[gy][gx];
				if (touching)
				{
					dd_touch_this(touching);
				} // touching
			} // sanity
		} // loop
	} // loop
}

function dd_dirRTction(ax,ay,bx,by) // if the world was square
{
	if      ((ay>by)&&(ax==bx)) return dirUP;
	else if ((ay<by)&&(ax==bx)) return dirDN;
	else if ((ax<bx)&&(ay==by)) return dirRT;
	else if ((ax>bx)&&(ay==by)) return dirLF;
	else if ((ay>by)&&(ax<bx)) return dirUR;
	else if ((ay>by)&&(ax>bx)) return dirUL;
	else if ((ay<by)&&(ax<bx)) return dirDR;
	else if ((ay<by)&&(ax>bx)) return dirDL;
	else return dirNONE;
}

function dd_direction(ax,ay,bx,by) // the is isometric
{
	// threshold of 4 pixels means close enough?
	//if (Math.abs(ax-bx) < 4) ax=bx;
	//if (Math.abs(ay-by) < 4) ay=by;
	
	pax = grid_to_pixelX(ax,ay);
	pbx = grid_to_pixelX(bx,by);
	pay = grid_to_pixelY(ax,ay);
	pby = grid_to_pixelY(bx,by);
	
	// threshold of 4 pixels means close enough?
	//if (Math.abs(pax-pbx) < 4) pax=pbx;
	//if (Math.abs(pay-pby) < 4) pay=pby;
	
	if      ((pay>pby)&&(pax==pbx)) return dirUP;
	else if ((pay<pby)&&(pax==pbx)) return dirDN;
	else if ((pax<pbx)&&(pay==pby)) return dirRT;
	else if ((pax>pbx)&&(pay==pby)) return dirLF;
	else if ((pay>pby)&&(pax<pbx)) return dirUR;
	else if ((pay>pby)&&(pax>pbx)) return dirUL;
	else if ((pay<pby)&&(pax<pbx)) return dirDR;
	else if ((pay<pby)&&(pax>pbx)) return dirDL;
	else return dirNONE;
}

function dd_walk_towards(personNUMBER,maxloops)
{
	walk_think_delay=360; // 240; // CORRECT MOVEMENT V2 360; // was 250
	movedebug=dd_v2_debug;			// chatter when we stop.
	//trygoingaroundthings=true; 	// sometimes walks into a wall?

	thisperson = dd_people[personNUMBER];
	if (!thisperson)
	{
		//alert('dd_walk_towards got a null pointer!');
		return; 
	}
					
	thisperson.dd_currently_walking = false; // reset

	maxloops--; // countdown to giving up
	if (maxloops < 0) 
	{
		if (movedebug) dd_chatter('DEBUG: I am giving up any more movement!',0,0,personNUMBER);
		//alert('giving up!');
		// OLD MOVEMENT WORKS:
		if (!thisperson.dd_walk_v2) thisperson.ele.src=thisperson.anim_stand_SW.src;//stop!
		return; // give up
	}

	thisgridx = thisperson.dd_walk_target_gx;
	thisgridy = thisperson.dd_walk_target_gy;

	feetXoffset = (thisperson.width / 2);
	feetYoffset = -thisperson.height + 16;
	feetpixelx= thisperson.getLeft() + feetXoffset - AVATAR_X_NUDGE;
	feetpixely= thisperson.getTop() - feetYoffset - AVATAR_Y_NUDGE;
	feetgridx = pixel_to_gridX(feetpixelx,feetpixely);
	feetgridy = pixel_to_gridY(feetpixelx,feetpixely);
	
	// remember where we are standing for other routines
	thisperson.gridX = feetgridx;
	thisperson.gridY = feetgridy;
	thisperson.pixelX = feetpixelx;
	thisperson.pixelY = feetpixely;
	
	if (movedebug) dd_chatter('Moving.' +
		' feet=' + feetgridx + ',' + feetgridy + 
		'=' + dd_img[feetgridy][feetgridx] +
		' click=' + thisgridx + ',' + thisgridy + 
		'=' + dd_img[thisgridy][thisgridx] +
		' feetp=' + feetpixelx + ',' + feetpixely
		,0,0,personNUMBER)

	very_close_x = very_close_y = false;
	/*
	if (!(thisgridy % 2)) 
	{	// even rows have rounding errors
		targetpixelx = grid_to_pixelX(thisgridx,thisgridy) + 24; // centered +24 +12
		targetpixely = grid_to_pixelY(thisgridx,thisgridy) + 12;
		fxdist = Math.abs(feetpixelx - targetpixelx);
		fydist = Math.abs(feetpixely - targetpixely);
		very_close_x = (fxdist < 24);
		very_close_y = (fydist < 12);
		if (dd_v2_debug)
		{ 
			if (very_close_x && very_close_y) 
				alert('Very close!  Avoiding the wiggle. fxdist='+fxdist+' fydist='+fydist);
			else
				alert('Not close yet. fxdist='+fxdist+' fydist='+fydist);
		}
	}
	*/
	
	
	// already there!			
	if 	((feetgridx == thisgridx) && (feetgridy == thisgridy) || (very_close_x && very_close_y))
	{
		if (movedebug) dd_chatter('DEBUG: Arrived at my destination!' + 
			' feet=' + feetgridx + ',' + feetgridy + 
			'=' + dd_img[feetgridy][feetgridx] +
			' target=' + targetgridx + ',' + targetgridy +
			'=' + dd_img[targetgridy][targetgridx] +
			' click=' + thisgridx + ',' + thisgridy + 
			'=' + dd_img[thisgridy][thisgridx] +
			' feetp=' + feetpixelx + ',' + feetpixely
			,0,0,personNUMBER);
		//alert('dd_walk_towards arrived!');
		thisperson.dd_currently_walking = false;
		// react to things under my feet and beside me when stopping
		dd_touch(personNUMBER,feetgridx,feetgridy);
		// OLD MOVEMENT:
		if (!thisperson.dd_walk_v2) thisperson.ele.src=thisperson.anim_stand_S.src;//stop anim
		return;
	}
	
	targetgridx = thisgridx;
	targetgridy = thisgridy;
	








	
	// one space away only - the isometrica messes this up
	//if (thisgridx > feetgridx) targetgridx = feetgridx + 1;
	//else if (thisgridx < feetgridx) targetgridx = feetgridx - 1;
	//else targetgridx = thisgridx;
	/*
	// since y is shifted, avoid zigzags by skipping a row!
	if (thisgridy > feetgridy) 
	{
		//if ((thisgridy - feetgridy) > 1) // far away?
		//	targetgridy = feetgridy + 2;
		//else // one space away
			targetgridy = feetgridy + 1;
	}
	else if (thisgridy < feetgridy)
	{
		//if ((feetgridy - thisgridy) > 1) // far away?
		//	targetgridy = feetgridy - 2;
		//else // one space away
			targetgridy = feetgridy - 1;
	}
	else targetgridy = thisgridy;
	*/





	
	// force inside map grid range!
	if (feetgridx < 0) feetgridx = 0;
	if (thisgridx < 0) thisgridx = 0;
	if (targetgridx < 0) targetgridx = 0;
	if (feetgridy < 0) feetgridy = 0;
	if (thisgridy < 0) thisgridy = 0;
	if (targetgridy < 0) targetgridy = 0;
	if (feetgridx > max_grid_X-1) feetgridx = max_grid_X-1;
	if (thisgridx > max_grid_X-1) thisgridx = max_grid_X-1;
	if (targetgridx > max_grid_X-1) targetgridx = max_grid_X-1;
	if (feetgridy > max_grid_Y-1) feetgridy = max_grid_Y-1;
	if (thisgridy > max_grid_Y-1) thisgridy = max_grid_Y-1;
	if (targetgridy > max_grid_Y-1) targetgridy = max_grid_Y-1;
	
	// big debug info
	//alert('DEBUG dd_walk_towards:' +
	//' feet= ' + feetgridx + ',' + feetgridy + 
	//' target=' + targetgridx + ',' + targetgridy +
	//' click= ' + thisgridx + ',' + thisgridy + 
	//' feetimg=' + dd_img[feetgridy][feetgridx] +
	//' targetimg=' + dd_img[targetgridy][targetgridx] +
	//' clickimg=' + dd_img[thisgridy][thisgridx]);

	// react to things under my feet and beside me while walking
	dd_touch(personNUMBER,feetgridx,feetgridy);

	found_a_way = false; 
	////////////////////////////////////////////////////////////////////
	//if (personNUMBER > 1) found_a_way = true; // only Player1 has to collide!!
	////////////////////////////////////////////////////////////////////

	/*
	if (dd_img[feetgridy][feetgridx] != '') // INSIDE SOMETHING - always allow exit
	{
		if (movedebug) dd_chatter('DEBUG: STUCK!  Getting out.' + 
			' feet=' + feetgridx + ',' + feetgridy + 
			'=' + dd_img[feetgridy][feetgridx] +
			' target=' + targetgridx + ',' + targetgridy +
			'=' + dd_img[targetgridy][targetgridx] +
			' click=' + thisgridx + ',' + thisgridy + 
			'=' + dd_img[thisgridy][thisgridx]
			,0,0,personNUMBER)
		found_a_way=true; // unstick
		wasblocked=0;
		thisperson.wasblockedlasttime=false;
	}
	else
	*/


	if (!found_a_way)
	{
		wasblocked = dd_blocked(feetgridx,feetgridy,targetgridx,targetgridy);
		if (wasblocked==0)
		{	// can get there dirRTctly
			found_a_way = true;
			thisperson.wasblockedlasttime=false;
			thisperson.last_good_gx = feetgridx;
			thisperson.last_good_gy = feetgridy;
		}
		else if (wasblocked==1)
		{	// way is blocked
			if (movedebug) dd_chatter('DEBUG: Blocked.' + 
				' feet=' + feetgridx + ',' + feetgridy + 
				'=' + dd_img[feetgridy][feetgridx] +
				' target=' + targetgridx + ',' + targetgridy +
				'=' + dd_img[targetgridy][targetgridx] +
				' click=' + thisgridx + ',' + thisgridy + 
				'=' + dd_img[thisgridy][thisgridx]
				,0,0,personNUMBER);
			found_a_way = false;
		}
		else if (wasblocked==-1) // special case: STUCK inside a prop!
		{	// FORCE DOWNWARD WALK NO MATTER WHAT!
			if (movedebug) dd_chatter('DEBUG: STUCK inside an object.' + 
				' feet=' + feetgridx + ',' + feetgridy + 
				'=' + dd_img[feetgridy][feetgridx] +
				' target=' + targetgridx + ',' + targetgridy +
				'=' + dd_img[targetgridy][targetgridx] +
				' click=' + thisgridx + ',' + thisgridy + 
				'=' + dd_img[thisgridy][thisgridx]
				,0,0,personNUMBER);
			//alert('I am stuck.  Moving to last known good grid position.');
			found_a_way = true; // let me move!
			//targetgridx=feetgridx;
			//targetgridy=feetgridy+1;
			if ((thisperson.last_good_gx) && (thisperson.last_good_gy))
			{
				targetgridx = thisperson.last_good_gx;
				targetgridy = thisperson.last_good_gy;
			}

		}
	} // if not stuck


	/*
	// sometimes gets stuck!
	// this sometimes makes a mistake and walks into a wall:
	if (!found_a_way && !thisperson.wasblockedlasttime && trygoingaroundthings)
	// try going around it

	{
		if (movedebug) dd_chatter('DEBUG: Blocked.  Trying to go AROUND.' + 
			' feet=' + feetgridx + ',' + feetgridy + 
			'=' + dd_img[feetgridy][feetgridx] +
			' target=' + targetgridx + ',' + targetgridy +
			'=' + dd_img[targetgridy][targetgridx] +
			' click=' + thisgridx + ',' + thisgridy + 
			'=' + dd_img[thisgridy][thisgridx]
			,0,0,personNUMBER)
		if (dd_blocked(feetgridx,feetgridy,targetgridx+1,targetgridy)==0) 
		{	// can go around y
			targetgridx++; 
			found_a_way = true;
			thisperson.wasblockedlasttime=true;
		}
		else if (dd_blocked(feetgridx,feetgridy,targetgridx-1,targetgridy)==0) 
		{	// can go around y
			targetgridx--; 
			found_a_way = true;
			thisperson.wasblockedlasttime=true;
		}
		else if (dd_blocked(feetgridx,feetgridy,targetgridx,targetgridy+1)==0) 
		{	// can go around x
			targetgridy++;
			found_a_way = true;
			thisperson.wasblockedlasttime=true;
		}
		else if (dd_blocked(feetgridx,feetgridy,targetgridx,targetgridy-1)==0) 
		{	// can go around x
			targetgridy--;
			found_a_way = true;
			thisperson.wasblockedlasttime=true;
		}
	}
	*/

	
	if (!found_a_way) // still totally blocked?
	{
		//dd_chatter('I am totally blocked and giving up movement.',0,0,personNUMBER)
		thisperson.dd_currently_walking = false; // stop
		thisperson.wasblockedlasttime=false; // reset
		// react to things under my feet and beside me when stopping
		dd_touch(personNUMBER,feetgridx,feetgridy);
		// OLD MOVEMENT:
		if (!thisperson.dd_walk_v2) thisperson.ele.src=thisperson.anim_stand_N.src; // stop
		
		return;
	}

	thisdir = dd_direction(feetgridx,feetgridy,targetgridx,targetgridy);

	if ((thisperson.last_dir) && (thisdir != thisperson.last_dir) && (thisdir == thisperson.lastlast_dir))
	{
		if (movedebug) dd_chatter('DEBUG: Close enough.' +
			' feet=' + feetgridx + ',' + feetgridy + 
			'=' + dd_img[feetgridy][feetgridx] +
			' target=' + targetgridx + ',' + targetgridy +
			'=' + dd_img[targetgridy][targetgridx] +
			' feetp=' + feetpixelx + ',' + feetpixely + 
			' click=' + thisgridx + ',' + thisgridy + 
			'=' + dd_img[thisgridy][thisgridx]
			,0,0,personNUMBER)
		thisperson.last_dir = false;
		thisperson.lastlast_dir = false;
		found_a_way = false;
		return;
	}

	//alert('NOT BLOCKED - dd_alt[' + gridx + '][' + gridy + ']=' + blocked);

	if (!thisperson.dd_walk_v2) // OLD ANIMATION NOT USED
	{
		// OLD MOVEMENT WORKS OKAY:
		// pixels snapped to grid
		myshadow = thisperson.ddshadow;
		GRIDpixelX = grid_to_pixelX(targetgridx,targetgridy);
		GRIDpixelY = grid_to_pixelY(targetgridx,targetgridy);
		// offset so their feet touch the spot
		gotoX = GRIDpixelX + feetXoffset;
		gotoY = GRIDpixelY + feetYoffset;
		//thisdir = dd_dirRTction(feetgridx,feetgridy,targetgridx,targetgridy);
		thisperson.slideTo(gotoX,gotoY); // nice cbe SLIDE has accel and deceleration
		if (myshadow) myshadow.slideTo(gotoX, gotoY+thisperson.height-22);
		// FIXME: changing to blank gif then back to anim RESTARTS the gif anim in IE - this is a hack!

		//alert('Debug: dd_dirRTction('+feetgridx+','+feetgridy+','+targetgridx+','+targetgridy+')='+thisdir);
		if (thisdir==dirUP) 	 { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_N.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		else if (thisdir==dirDN)  { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_S.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		else if (thisdir==dirRT)  { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_E.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		else if (thisdir==dirLF)  { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_W.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		else if (thisdir==dirUR) { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_NE.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		else if (thisdir==dirDR) { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_SE.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		else if (thisdir==dirUL) { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_NW.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		else if (thisdir==dirDL) { thisperson.ele.src='fx_blank.gif'; thisperson.ele.src=thisperson.anim_walk_SW.src; } // +'?'+Math.random();} //animate(DOWNLOAD!)
		thisperson.setZIndex(dd_zin[targetgridy][targetgridx]); // take target z-index NOW! FIXME do each alide anim step
	}
	else
	{
		thisperson.lastlast_dir = thisperson.last_dir;

		// NEW MOVEMENT AND ANIMATION
		//thisdir = dd_direction(feetgridx,feetgridy,thisperson.dd_walk_target_gx,thisperson.dd_walk_target_gy); //targetgridx,targetgridy);
		thisdir = dd_direction(feetgridx,feetgridy,targetgridx,targetgridy);
		////thisperson.last_dir = thisdir;
		//thisperson.lastlastlast_feetgridx = thisperson.lastlast_feetgridx;
		//thisperson.lastlastlast_feetgridy = thisperson.lastlast_feetgridy;
		//thisperson.lastlast_feetgridx = thisperson.last_feetgridx;
		//thisperson.lastlast_feetgridy = thisperson.last_feetgridy;
		//thisperson.last_feetgridx = feetgridx;
		//thisperson.last_feetgridy = feetgridy;

		/* spammy
		if (movedebug) dd_chatter('DEBUG: walk('+maxloops+'):'+thisperson.dd_walk_target_gx+','+thisperson.dd_walk_target_gy+
				' target:'+targetgridx+','+targetgridy+
				' feet:'+feetgridx+','+feetgridy
				+ ' dir:'+thisdir+' dir1:'+thisperson.last_dir+' dir2:'+thisperson.lastlast_dir+'.',0,0,personNUMBER)
				// + ' lasttarget:'+thisperson.last_targetgridx+','+thisperson.last_targetgridy+'.',0,0,personNUMBER)
		*/
		
		thisperson.last_dir = thisdir;
		thisperson.dd_walk_v2(thisdir,6); // start walking 6 frames
		
		newZ = dd_zin[targetgridy][targetgridx];
		if (newZ)
		{
			thisperson.setZIndex(newZ); // take target z-index NOW! FIXME do each alide anim step
			if (thisperson.ddclothing) thisperson.ddclothing.setZIndex(newZ+1);
			if (thisperson.ddhat) thisperson.ddhat.setZIndex(newZ+2);
			if (thisperson.ddextra) thisperson.ddextra.setZIndex(newZ+3);
		}

	}
	
	// and keep calling this function recursively until we arrive.
	thisperson.dd_currently_walking = true;
	setTimeout('dd_walk_towards('+personNUMBER+','+maxloops+')',walk_think_delay); // 1 sec to travel 2 squares?
		
} // dd_walk_towards()






function dd_mousemove()
{
	if ((dd_dragging))// && (!is.mac))
	{
		dd_dragging.setTop(currentMouseY+dd_dragging.dragYoffset);
		dd_dragging.setLeft(currentMouseX+dd_dragging.dragXoffset);
	}
	
	update_gridXY();//shootout and look_at
	
	if ((Player1) && (!Player1.dd_currently_walking)) 
	{
		if (dd_can_stand(currentGridX,currentGridY))
		{
			mousedirection = dd_direction(Player1.gridX,Player1.gridY,currentGridX,currentGridY);
			//dd_debugme('Click to walk ['+mousedirection+'] to '+currentGridX+','+currentGridY);
			Player1.dd_look_at(mousedirection);
		}
		//else dd_debugme('Cannot get to '+currentGridX+','+currentGridY);
	}

}
function netscapeMouseMove(e) 
{ 
	if (!dd_loaded) return; 
	currentMouseX = e.pageX;  
	currentMouseY = e.pageY; 
	dd_mousemove();
}
function microsoftMouseMove() 
{ 
	if (!dd_loaded) return; 
	currentMouseX = window.event.clientX; 
	currentMouseY = window.event.clientY; 
	dd_mousemove();
}


function netscapeMouseClick(e) 
{ 
	if (!dd_loaded) return;
	if (dd_ignore_next_click) { dd_ignore_next_click = false; return; }
	currentMouseX = e.pageX;
	//if (document.dd_form.px) document.dd_form.px.value = e.pageX;
	currentMouseY = e.pageY; 
	//if (document.dd_form.py) document.dd_form.py.value = e.pageY
	update_gridXY();
	//alert('netscapeMouseClick(' + currentMouseX + ',' + currentMouseY + ')');
	dd_click();
}

function microsoftMouseClick() 
{ 
	if (!dd_loaded) return; 
	if (dd_ignore_next_click) { dd_ignore_next_click = false; return; }
	currentMouseX = window.event.clientX; 
	//if (document.dd_form.px) document.dd_form.px.value = window.event.clientX; 
	currentMouseY = window.event.clientY; 
	//if (document.dd_form.py) document.dd_form.py.value = window.event.clientY; 
	update_gridXY();
	dd_click();
}











function dd_remove_inventory(anitem)
{
	if (dd_v2_debug) alert('DEBUG: dd_remove_inventory('+anitem+') was:'+player_inventory);
	if (string_contains(player_inventory,anitem))
	{
		player_inventory = dd_str_replace(anitem,'',player_inventory); // removes ALL matches
		player_inventory = dd_str_replace(',,',',',player_inventory);
		player_inventory = dd_str_replace(',,',',',player_inventory);
		player_inventory = dd_str_replace(',,',',',player_inventory);
		player_inventory = dd_str_replace(',,',',',player_inventory);
		player_inventory = dd_str_replace(',,',',',player_inventory);
		player_inventory = dd_str_replace(',,',',',player_inventory);
		player_inventory = dd_str_replace(',,',',',player_inventory);
		player_inventory = dd_str_replace(',,',',',player_inventory);
		if (player_inventory == ',') player_inventory = '';
	}
	if (dd_v2_debug) alert('DEBUG: dd_remove_inventory('+anitem+') now:'+player_inventory);
}

function dd_wildbill_pistol() // special case NPC
{
	if (string_contains(player_inventory,'item_wbgun'))
	{
		dd_remove_inventory('item_wbgun');
		dd_refresh_inventory();
		player_legendstatus = "Wild Bill's Pard";
		dd_refresh_legendstatus('<font color=red>'+player_legendstatus+'</font>');
		setTimeout('dd_open_window(window_journal);',3000); // show the update
		newsubmit = 'dd_pixel.php?cmd2=legendstatus&val2='+player_legendstatus+'&cmd=inventory&val='+player_inventory+'&rand='+Math.random()+'&uid='+uid;
		if (dd_v2_debug) { if (!confirm('DEBUG: player_inventory=' + player_inventory + ' SUBMIT THIS? \n'+newsubmit)) return; }
		dd_submit_pixel(newsubmit);
		NPCchat(50);
	}
	else
	{
		NPCchat(51);
	}		
}


var wildbill_script = new Array();

function shootout_now() 
{
	dd_warp("gem_shootout1_flipped"); // 000_shoot
}

wildbill_script[0] =
"<br>Howdy Pard. Do I know you?" +
"<br><br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about Deadwood</a>";
// wild bill
wildbill_script[10] =
"<a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('wildbillhickok'); return false; \">Wild Bill</a> is just my nickname. My name's really James Butler, but my friends call me Bill. " +
"You can call me Mr. Hickok, at least 'til we have a little more civil conversation." +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Calamity Jane</a>";
// deadwood
wildbill_script[20] = 
"I came to <a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('deadwood'); return false; \">Deadwood</a> in July of 1876. I had a new wife back in Cheyenne, " +
"and I hoped I could find myself a little gold at the poker table and send for her later. " +
"<br><a class=chatURL href='javascript:NPCchat(24);' title='Click here to hear more.'>[more]</a>" +
"<br><a class=chatURL href='javascript:NPCchat(23);' title='Click here to hear more.'>Ask about wife</a>";
wildbill_script[22] = 
"<br>Deadwood was an illegal settlement on Indian Territory. There was no law back then. " +
"<br><br><a class=chatURL href='javascript:NPCchat(26);' title='Click here to hear more.'>[more]</a>";
wildbill_script[23] = 
"<br>Her name was Agnes... Agnes Lake Thatcher. We got married a few months before I came to Deadwood. " +
"<br><br><a class=chatURL href='javascript:NPCchat(29);' title='Click here to hear more.'>[more]</a>";
wildbill_script[24] =
"<br>The job of marshal wouldn't have been bad, either. But something happened a few days after I got here..." +
"I just can't remember." +
"<br><br><a class=chatURL href='javascript:NPCchat(22);' title='Click here to hear more.'>Ask about marshal job</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about being a ghost</a>";
wildbill_script[26] = 
"<br>I know some folks hoped I would become the unofficial sheriff and bring some order to the town. " +
"I had a reputation, you know. They called me the 'Prince of Pistoleers'.  " +
"<br><br><a class=chatURL href='javascript:NPCchat(28);' title='Click here to hear more.'>[more]</a>";
wildbill_script[28] = 
"<br>Speaking of which, I lost one of my pistols.  <b>Do you know where it might be?</b>" +
"<br><br><a class=chatURL href='javascript:dd_wildbill_pistol();' title='Click here to hear more.'>Give Wild Bill his pistol</a>";
wildbill_script[29] = 
"<br>I hoped I could find money and a home for my new family." +
"<br><br><a class=chatURL href='javascript:NPCchat(22);' title='Click here to hear more.'>Ask about marshal job</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Calamity Jane</a>";
// calamity
wildbill_script[30] = 
"<br><a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('calamityjane'); return false; \">Calamity Jane</a>?  Where? Is she here? Hide me! Sorry - I didn't mean to lose it. " +
"<br><br><a class=chatURL href='javascript:NPCchat(90);' title='Click here to hear more.'>[more]</a>";
wildbill_script[31] = 
"<br>We had a whirlwind relationship - I'd run like a twister from hell every time I'd see her." +
"The only romance we had was in her head." +
"<br><br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about being a ghost</a>" +
"<br><a class=chatURL href='javascript:NPCchat(23);' title='Click here to hear more.'>Ask about wife</a>";
// ghost
wildbill_script[40] = 
"<br>Ghost? Oh, right. It's easy to forget things when you're dead." +
"<br><br><a class=chatURL href='javascript:NPCchat(41);' title='Click here to hear more.'>Ask about death</a>" +
"<br><a class=chatURL href='javascript:NPCchat(22);' title='Click here to hear more.'>Ask about marshal job</a>";
wildbill_script[41] = 
"<br>Dead? That must have been it, but I can't seem to remember much about my last few days here. " +
"<br><br><a class=chatURL href='javascript:NPCchat(42);' title='Click here to hear more.'>[more]</a>";
wildbill_script[42] = 
"<br>Hey pard, could you find out what happened to me? I'd sure like to know." +
"<br><br><a class=chatURL href='javascript:NPCchat(60);' title='Click here to hear more.'>Tell Bill about his death</a>";
// bonus 1
wildbill_script[50] = 
"<br>I can't believe it - that's one of my pistols! You have my sincerest thanks.<br><font color=red><b>Legend Status Increased.</b></font>" +
"<br><br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"<br><br><a class=chatURL href='javascript:shootout_now();' title='Click here to PLAY THE SHOOTOUT GAME.'>[PLAY SHOOTOUT GAME]</a>" +
"";
wildbill_script[51] = 
"<br>You don't have my pistol!  Maybe you can find it around town.  Try asking the bartender where it is.  I'll make it worth your while..." +
"<br><br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"";
// bonus2
wildbill_script[60] = 
"<br>So that's how it ended. I remember now... can't say it's very heartening.  I know... " + 
"how about we do a little shooting? That always cheers me up. " +
"<br><br><a class=chatURL href='javascript:shootout_now();' title='Click here to PLAY THE SHOOTOUT GAME.'>[PLAY!]</a>";
//"<br><br><a class=chatURL href='javascript:NPCchat(62);' title='Click here to hear more.'>[more]</a>";
wildbill_script[62] = 
"<br>We can make it a contest. See if you can beat my score. " +
"We'll try shooting at those rocks over there. I'll go first, Okay?";
// more calamity
wildbill_script[90] = 
"<br>I wasn't scared of much when I was alive, and I'm not scared of anything now that I'm dead... " +
"anything except for that woman! " +
"<br><br><a class=chatURL href='javascript:NPCchat(92);' title='Click here to hear more.'>[more]</a>";
wildbill_script[92] = 
"<br>It wasn't enough that she chased me to the grave.  Nope, she took the burial plot next to mine, and now she'll " +
"chase me until Judgment Day!" +
"<br><br><a class=chatURL href='javascript:NPCchat(31);' title='Click here to hear more.'>Ask about romance</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about being a ghost</a>";



var bartender_script = new Array();
bartender_script[0] = 
"<br>Hey there. Can I get you something?<br>" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about business</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Order a drink</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"";
bartender_script[10] = 
"In winter the skiers and snowmobilers come in droves, spring is full of parties on Main Street, in summer and autumn we get crowds of people who enjoy the great outdoors. Business is great!" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Order a drink</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"";
bartender_script[20] = 
// (NO CASH) "Hey... what're you tryin' to pull? I'm afraid I can't give you anything unless you've got some cash." +
"<br>Sure. Feeling any better?<br>" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about business</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"";
bartender_script[30] = 
"Welcome to town! Most businesses are on Main Street: saloons, restaurants, hotels, gaming halls and a few shops. Mount Moriah is the cemetery on the mountain above town." +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about Main Street</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about Mount Moriah</a>" +
"";
bartender_script[40] = 
"Main Street is the brick paved road outside. It's been the hub of Deadwood since it was built in 1876. It's pretty long, so it'll take you a while to walk it. Remember to click FLIP to see both sides of the street." +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about Mount Moriah</a>" +
"<br><a class=chatURL href='javascript:NPCchat(60);' title='Click here to hear more.'>Ask about famous people</a>" +
"";
bartender_script[50] = 
"Use your Map Button and click on Mount Moriah to climb up to the cemetery. A lot of famous people are buried up there, like Seth Bullock, Preacher Smith, Potato Creek Johnny, Wild Bill, and Calamity Jane." +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about Main Street</a>" +
"<br><a class=chatURL href='javascript:NPCchat(60);' title='Click here to hear more.'>Ask about famous people</a>" +
"";
bartender_script[60] = // (USER DATABASE UPDATE: HAS SPOKEN WITH BARTENDER)
"Seth Bullock was the town's first sheriff, Preacher Smith was martyred after a sermon, and Potato Creek found the largest gold nugget in the Black Hills. " +
"<br><a class=chatURL href='javascript:NPCchat(61);' title='Click here to hear more.'>[more]</a>" +
"";
bartender_script[61] = // (USER DATABASE UPDATE: HAS SPOKEN WITH BARTENDER)
"Wild Bill and Calamity Jane are two of the most famous people in Deadwood.  Try talking to the re-enactors on Main Street or walk up to the cemetery sometime. I hear it's haunted..." +
// (IF USER HAS SPOKEN TO WILDBILL)
"<br><a class=chatURL href='javascript:NPCchat(70);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about Mount Moriah</a>" +
"<br><a class=chatURL href='javascript:NPCchat(60);' title='Click here to hear more.'>Ask about famous people</a>" +
"";
bartender_script[70] =
"So, you want to know about Wild Bill? You came to the right place, because he died in this very bar. There's a reenactment here every night in the summer, but I can tell you the story." +
"<br><a class=chatURL href='javascript:NPCchat(72);' title='Click here to hear more.'>[more]</a>" +
"";
bartender_script[72] =
"Bill had been in Deadwood for a couple of weeks when he strolled in here on August 2nd, 1876. He always sat with his back to the wall and held his cards in his left hand, just in case someone tried to walk in and surprise him from behind." +
"<br><a class=chatURL href='javascript:NPCchat(74);' title='Click here to hear more.'>[more]</a>" +
"";
bartender_script[74] =
"Unfortunately, the bar was packed and the only seat open at the card table exposed his back to the door. Bill took the seat anyway, but he didn't live to regret it." +
"<br><a class=chatURL href='javascript:NPCchat(76);' title='Click here to hear more.'>[more]</a>" +
"";
bartender_script[76] =
"Jack McCall, a lonely drifter who claimed Bill had shot his brother, walked in and put a bullet right into the back of the legend's head." +
"<br><a class=chatURL href='javascript:NPCchat(78);' title='Click here to hear more.'>[more]</a>" +
"";
bartender_script[78] =
"They caught up with McCall later in the eastern part of Dakota Territory,  and they hanged him for murder. Hmph. Frontier justice. Anyway, is there anything else you needed?" +
"<br><a class=chatURL href='javascript:NPCchat(80);' title='Click here to hear more.'>Ask about Wild Bill's pistols</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Order a drink</a>" +
"";
bartender_script[80] =
"Well, I know the Adams Museum had a Wild Bill pistol for a long time, but I think it disappeared decades ago. No one really knows, but rumor has it that it's still in Deadwood." +
"<br><a class=chatURL href='javascript:NPCchat(82);' title='Click here to hear more.'>[more]</a>" +
"";
bartender_script[82] =
"You could try looking over by the Old Franklin Garage building at the top of Main Street, or maybe the Wing Tsue building down in old Chinatown." +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about business</a>";
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Order a drink</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"";



var calamity_script = new Array();
calamity_script[0] = 
"Howdy stranger! Would you like to see some real ropin' action? Yee-haw!" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Calamity Jane</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about drinking</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
calamity_script[10] = 
"Ha-raaaoooooooh! I'm a howling coyote from Bitter Creek, the further up you go the bitterer it gets, and I'm from the head end!" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
calamity_script[20] = 
"<br>Drink? You can buy me a drink anytime ya like - just come 'an find me! Ha-raaaoooohhhh!<br>" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Calamity Jane</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
calamity_script[30] = 
"<br>The love of my life! The darling! God rest his departed soul and body on Mount Moriah.<br>" +
"<br><a class=chatURL href='javascript:NPCchat(31);' title='Click here to hear more.'>Ask about Mount Moriah</a>" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Calamity Jane</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
calamity_script[31] = 
"Use your map button to take a hike up the mountain and visit the grave of my dearly beloved. Rumor says the place is haunted, but I don't believe it. The ghost of my only love has never come out to see me..." +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
calamity_script[40] = 
"I came here back in 1876 with all the other prospectors. I spent a lot of my life here in these Hills... You know, it doesn't look much different today than it did back in 1900." +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Calamity Jane</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(50);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
calamity_script[50] = 
"<br>Ha-raaooooooh!<br>" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about Calamity Jane</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about drinking</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about Wild Bill</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about Deadwood</a>" +
"";







var pcj_script = new Array();
pcj_script[0] =
"<br>Hey there young feller!<br>" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about his name</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about his height</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about prospecting</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
pcj_script[10] =
"Potato Creek is where I found my gold nugget - the largest ever found in the Black Hills! One day in 1927 I walked down from my cabin, did some panning in the creek, and in seconds I was a wealthy man." +
// Some people call me the last successful prospector in the country.
"<br><a class=chatURL href='javascript:NPCchat(11);' title='Click here to hear more.'>Ask about nugget</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about prospecting</a>" +
"";
pcj_script[11] =
"My nugget weighed almost 8 troy ounces - that's over half a pound! It's in the Adams Museum now. That's over on Sherman Street, if you'd like to go there sometime." +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about his height</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about prospecting</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
pcj_script[20] =
"So I'm only four feet, three inches tall. Prospecting is hard work no matter how big you are!" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about his name</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about prospecting</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
pcj_script[30] =
"When I came to the Black Hills from Wales in 1883, we prospectors could just pick the gold right out of the creeks. It wasn't long before that was all gone, and we miners had to get smarter. We dug deep, blasting as far down as we dared. " +
" <a class=chatURL href='javascript:NPCchat(31);' title='Click here to hear more.'>[more]</a>" +
"";
pcj_script[31] =
"Anyone could make their fortunes back then... Of course, Lady Luck has moved from the creeks and mine shafts to the card tables and slot machines nowadays." +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about his name</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about his height</a>" +
"<br><a class=chatURL href='javascript:NPCchat(40);' title='Click here to hear more.'>Ask about being an actor</a>" +
"";
pcj_script[40] =
"<br>Visit my grave up on Mount Moriah! Heh heh heh!<br>" +
"<br><a class=chatURL href='javascript:NPCchat(10);' title='Click here to hear more.'>Ask about his name</a>" +
"<br><a class=chatURL href='javascript:NPCchat(20);' title='Click here to hear more.'>Ask about his height</a>" +
"<br><a class=chatURL href='javascript:NPCchat(30);' title='Click here to hear more.'>Ask about prospecting</a>" +
"";


var silverado_script = new Array();
silverado_script[0] = '<br>We give away two FREE cars a month every month during our <a class=chatURL title="Click here to open a new window and continue playing." target="_blank" href="http://www.silveradocasino.com/car.html?from=DigitalDeadwood">Great Car Giveaway</a>!';
silverado_script[1] = '<br>Every Friday and Saturday eat all the Snow Crab you can crack! <a class=chatURL title="Click here to open a new window and continue playing." target="_blank" href="http://www.digitaldeadwood.com/promos/silverado_buffet_coupon.gif?from=DigitalDeadwood">Click here</a> for a $1.00 off coupon.';
silverado_script[2] = '<br><a class=chatURL title="Click here to open a new window and continue playing." target="_blank" href="http://www.silveradocasino.com/winsome.html?from=DigitalDeadwood">Win$ome Wednesdays</a> is our FREE $500 slot tournament for Sensational Seniors club members.';
silverado_script[3] = '<br>Sign up for $5,000 Fridays, our weekly slot tournament that&#8217;s free for <a class=chatURL title="Click here to open a new window and continue playing." target="_blank" href="http://www.silveradocasino.com/pclub.html?from=DigitalDeadwood">Players Club</a> members.';
silverado_script[4] = '<br>Visit us at the <a class=chatURL title="Click here to open a new window and continue playing." target="_blank" href="http://www.silveradocasino.com/?from=DigitalDeadwood">Silverado</a> today to pick up your &#8220;Win it. Ride it!&#8221; card for a chance to win a new golf cart!';


var NPC_shut_up = false;

function NPCchat(current_script_line)
{
	if (NPC_shut_up) return;

	if (!current_script_line) current_script_line = 0;
	
	var chatstr = null;
	
	if ((map=='000_shoot') || (map == 'gem_shootout1_flipped')) // Shootout
	{
		chatstr = "<center><a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('wildbillhickok'); return false; \">Wild Bill Hickok</a></center> ";
		chatstr += "Shootout at high noon!<br><br><b>The Deadeye Gang</b><br><br>(Shoot badguys by clicking on them when they appear)";
		setTimeout('bub0.hide()',5000); // shut up
		NPC_shut_up=true;
	}
	else if (map=='mm_flipped') // Wild Bill!
	{
		if (current_script_line >= wildbill_script.length) current_script_line=0;
		if (!wildbill_script[current_script_line]) current_script_line = 0;
		chatstr = "<center><a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('wildbillhickok'); return false; \">Wild Bill Hickok</a></center> ";
		chatstr += wildbill_script[current_script_line];
	}
	else if (map=='int_silver_flipped') // silverado girl
	{
		if (current_script_line >= silverado_script.length) current_script_line=0;
		if (!silverado_script[current_script_line]) current_script_line = 0;
		chatstr = "<center><a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('707mainstreet'); return false; \">Silverado Casino</a></center> ";
		chatstr += silverado_script[current_script_line];
		current_script_line++; // cycle ads
		setTimeout('bub0.hide()',6000); // shut up
		setTimeout('NPCchat('+current_script_line+');',30000); // cycle ads
	}
	else if (map=='saloon10_flipped') // bartender
	{
		if (current_script_line >= bartender_script.length) current_script_line=0;
		if (!bartender_script[current_script_line]) current_script_line = 0;
		chatstr = "<center><font color=#888888>Bartender</font></center> ";
		chatstr += bartender_script[current_script_line];
	}
	else if (map=='611_main_e_flipped') // calamity
	{
		if (current_script_line >= calamity_script.length) current_script_line=0;
		if (!calamity_script[current_script_line]) current_script_line = 0;
		chatstr = "<center><a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('calamityjane'); return false; \">Calamity Jane</a></center> ";
		chatstr += calamity_script[current_script_line];
	}
	else if (map=='700_main_w') // pcj
	{
		if (current_script_line >= pcj_script.length) current_script_line=0;
		if (!pcj_script[current_script_line]) current_script_line = 0;
		chatstr = "<center><a class=chatURL href=' ' title='[ HISTORYLINK ]' onclick=\"dd_history_link('potatocreekjohnny'); return false; \">Potato Creek Johnny</a></center> ";
		chatstr += pcj_script[current_script_line];
	}

	if (chatstr) 
		dd_chatter(chatstr,0,0,NPCSLOT);//2); // bot talk
}

function dd_ai_tick() /// NPC movement and chat
{
	ai_giveup_squares = 4; // spaces to try to move - can give up INSIDE a prop... fixme
	//alert('DEBUG: dd_ai_tick');

	ai_x = dd_random_int(max_grid_X-1);
	ai_y = dd_random_int(max_grid_Y-4)+4; // not too close to top
	
	// NPC bot only goes if allowed
	if (dd_can_stand(ai_x,ai_y))	// only choose it if it contains nothing
		dd_start_walking_towards(NPCSLOT,ai_x,ai_y,ai_giveup_squares); // NPCSLOT was 2

	setTimeout('dd_ai_tick()',10000); // 10000 = 10 sec per AI thought
	
}

imagecache=new Array(); // images are held unused in RAM here for faster animation
function dd_preload() 
{ 
	if (dd_v2_debug && document.chatform) document.chatform.mychat.value='DEBUG MODE - Loading GUI images...';

	for(i=0; i < pics.length; i++) 
	{ 
		imagecache[i]=new Image(); 
		imagecache[i].src=pics[i]; 
	} 
}
dd_preload();


function dd_teleport(botnum,px,py)
{
	if (dd_people[botnum])
	{
		thisperson = dd_people[botnum];
		
		if (thisperson.timestamp) thisperson.timestamp.getTime(); // not idle now
		
		thisperson.height = thisperson.getHeight();
		thisperson.width = thisperson.getWidth();
		
		//alert('DEBUG: dd_teleport bot # ' + botnum + ' to ('+px+','+py+') name=' + thisperson.playername);

		thisperson.moveTo(px,py);

		if (thisperson.ddclothing) thisperson.ddclothing.moveTo(px,py);
		if (thisperson.ddhat) thisperson.ddhat.moveTo(px,py);
		if (thisperson.ddextra) thisperson.ddextra.moveTo(px,py);
		if (thisperson.ddshadow) thisperson.ddshadow.moveTo(px,py+thisperson.height-22);
		if (thisperson.ddnametag) thisperson.ddnametag.moveTo(px-48,py+thisperson.height);
		//if (thisperson.ddbubba) ddbubba.moveTo(px,py-72);//80);

		//targetgridx = pixel_to_gridX(px+thisperson.width / 2,py+thisperson.height-16);
		//targetgridy = pixel_to_gridY(px+thisperson.width / 2,py+thisperson.height-16);
		targetgridx = pixel_to_gridX(px,py); // sent incorrectly
		targetgridy = pixel_to_gridY(px,py);
	
		if (dd_zin[targetgridy])
		{
			newZ = dd_zin[targetgridy][targetgridx];
			if (newZ)
			{
				thisperson.setZIndex(newZ); 
				if (thisperson.ddclothing) thisperson.ddclothing.setZIndex(newZ+1);
				if (thisperson.ddhat) thisperson.ddhat.setZIndex(newZ+2);
				if (thisperson.ddextra) thisperson.ddextra.setZIndex(newZ+3);

				if (thisperson.ddnametag) thisperson.ddnametag.setZIndex(newZ+4);
				//alert('Teleported and changed z-index to ' + newZ);
			}
		}

		thisperson.show();
		if (thisperson.ddclothing) thisperson.ddclothing.show();
		if (thisperson.ddhat) thisperson.ddhat.show();
		if (thisperson.ddextra) thisperson.ddextra.show();
		if (thisperson.ddshadow) thisperson.ddshadow.show();
		if (thisperson.ddnametag) 
		{
			thisperson.ddnametag.ele.innerHTML=thisperson.playername;
			thisperson.ddnametag.show();
		}
		//if (thisperson.ddbubba) thisperson.ddbubba.show();

		//alert('Teleported and SHOWING!');
	}

}

function dd_teleport_name(botname,px,py)
{
	//if (dd_v2_debug) alert('DEBUG: dd_teleport_name name=' + botname);
	botnum = dd_name_to_num(botname);
	if (dd_people[botnum])
	{
		dd_teleport(botnum,px,py);
	}
	
}

function dd_destroy_bot(you)
{
	if (!you) return;

	if (you.playername==playername) return; // no self destruct.
	if (you==Player1) return; // no self destruct.
	
	if (dd_v2_debug) alert('DEBUG: Destroying bot name=' + you.playername + ' email=' + you.playeremail);

	you.hide(); 
	you.ele.src='cache.php?img=fx_blank.gif';
	
	if (you.ddclothing) 	{ you.ddclothing.hide(); you.ddclothing.ele.src='cache.php?img=fx_blank.gif'; }
	if (you.ddhat) 		{ you.ddhat.hide(); you.ddhat.ele.src='cache.php?img=fx_blank.gif'; }
	if (you.ddextra) 	{ you.ddextra.hide(); you.ddextra.ele.src='cache.php?img=fx_blank.gif'; }
	if (you.ddshadow) 	{ you.ddshadow.hide(); }
	if (you.ddnametag) 	{ you.ddnametag.hide(); }
	if (you.ddbubba) 	{ you.ddbubba.hide(); }

	you.playername='';
	you.playeremail='';
		
}

function dd_destroy_bot_num(botnum)
{
	if (dd_people[botnum])
	{
		dd_destroy_bot(dd_people[botnum]);
	}
}

function dd_destroy_bot_name(botname)
{
	botnum = dd_name_to_num(botname);
	if (dd_people[botnum])
	{
		dd_destroy_bot(dd_people[botnum]);
	}
}

function dd_respawn(myname,mylook,mygx,mygy,myip,myemail,deleteme,teleport) // grab existing or create new avatar and move
{
	//return; // CK respawn turned off?
	
	//if (dd_v2_debug) alert('DEBUG['+playername+']: dd_respawn(n='+myname+', l='+mylook+', x='+mygx+', y='+mygy+', i='+myip+', e='+myemail+', d='+deleteme+', t='+teleport+')');

	if (myemail==playeremail)
	{
		//if (dd_v2_debug) alert('DEBUG['+playername+']: Ignoring a respawn from myself!');
		return;
	}
	
	if (!deleteme) deleteme=false; // undefined
	if (!teleport) teleport=false; // undefined

	//if (deleteme) alert('DEBUG['+playername+']: got a [-] message from ['+myname+']'); // debug

	tx = grid_to_pixelX(mygx,mygy) + AVATAR_X_NUDGE; // grid units
	ty = grid_to_pixelY(mygx,mygy) + AVATAR_Y_NUDGE; // grid units SHIFT ME -1?!

	blankperson = 0;
	foundnum=0;
	foundhim=null;
	foundit = false;
	for (var loopav=3; loopav < dd_people_count+1; loopav++) // v1 was var loopav=3
	{
		if (dd_people[loopav])
		{
			// change from AND to OR so "undefined" emails with same names still match!!
			if ( (string_contains(dd_people[loopav].playername,myname)) && 
			(string_contains(dd_people[loopav].playeremail,myemail)))
			{
				//if (loopav > 2) // sanity: player one and NPC needs no bot movement
				{
					foundnum = loopav;
					foundhim = dd_people[loopav];
					foundname = myname;
					foundemail = myname;

					foundit = true;
					
					if ((!teleport) && (!deleteme)) // normal msg: optimized
					{
		
						if (foundhim.timestamp) 
						{
							//alert('DEBUG: timestamping '+ foundhim.playername);
							foundhim.timestamp.getTime(); // not idle now
						}
						//if (dd_v2_debug) alert('DEBUG['+playername+']: About to move a FOUND person['+foundname+']!');
						// bots and npc's ALWAYS get to the right place
						//getthere = 'dd_teleport_name(\''+foundname+'\','+mygx+','+mygy+');';
						//setTimeout(getthere,10);
						dd_start_walking_towards(loopav,mygx,mygy,40);
						return; // STOP NOW!
					}

				}
					
			}
			else if ((dd_people[loopav].playername == '') && (dd_people[loopav].playeremail == ''))
			{
				blankperson = loopav;
			}

		}
	}
	
	if (teleport && foundit)
	{
		//if (dd_v2_debug) alert('DEBUG['+playername+']: Existing avatar ['+foundname+'] teleporting to '+tx+','+ty);
		//dd_teleport(foundnum,tx,ty);
		dd_teleport_name(foundname,tx,ty);
		return;
	}

	if (deleteme && foundit)
	{
		//if (dd_v2_debug) alert('DEBUG['+playername+']: Existing avatar ['+foundname+'] requesting DESTRUCTION!');
		//if (foundhim) dd_destroy_bot(foundhim);
		timeoutJS = 'dd_destroy_bot_name(\''+foundname+'\')';
		setTimeout(timeoutJS,5000); // 5 secs later
		return;
	}
	
	if ((!foundit) && (blankperson) && (!deleteme)) // we need a new avatar!
	{
		if (dd_people[blankperson])
		{
			spawn_me = dd_people[blankperson];
			//if (dd_v2_debug) alert('DEBUG['+playername+']: About to spawn a new person in slot ['+blankperson+'].  name='+myname+' email='+myemail+' look='+mylook);
			spawn_me.playername = myname;
			spawn_me.playeremail = myemail;
			spawn_me.look = mylook;
			//if (dd_v2_debug) alert('DEBUG['+playername+']: FRESH avatar ['+myname+'] is teleporting to '+tx+','+ty);
			
			if (spawn_me.timestamp) 
			{
				//alert('DEBUG: timestamping spawn '+ foundhim.playername);
				spawn_me.timestamp.getTime(); // not idle now
			}
			
			dd_teleport(blankperson,tx,ty);

			if ((spawn_me.ddnametag) && (spawn_me.ddnametag.ele))
			{
				spawn_me.ddnametag.ele.innerHTML = myname;
			}
			spawn_me.dd_preload_all_frames(mylook); // takes forever!


			return;
		}
	}

	if (dd_v2_debug)
	{
		alert('DEBUG['+playername+']: dd_respawn did not handle a message from '+ myname+' e='+myemail+', d='+deleteme+', t='+teleport );
	}
	
}

/*
function DOM_dd_respawn(myid,mylook,myname,mygx,mygy)
{
	alert('dd_respawn('+myid+','+myname+','+mygx+','+mygy+','+mylook+')');
	
	var img = new Image();
	img.src = 'cache.php?img=fx_blank.gif';
	
  	if (document.createElement) 
	{
		var element = document.getElementById('Player1');
  		var new_element = element.cloneNode(true); // true=all children too
		//var new_element = document.createElement('IMG');
		new_element.className = 'dd_spawned';
		new_element.src = img.src;
		new_element.id = myid;
		new_element.playername = myname;
		//new_element.ele = new_element;
		document.body.appendChild(new_element);

		var element2 = document.getElementById('Player1.ddshadow');
  		var new_element2 = element2.cloneNode(true); // true=all children too
		//var new_element2 = document.createElement('IMG');
		new_element2.className = 'dd_spawned_shadow';
		new_element2.src = img.src;
		new_element2.id = myid + '.ddshadow';
		new_element2.playername = myname;
		//new_element2.ele = new_element2;
		document.body.appendChild(new_element2);

	}
	else if (document.all) 
	{
		document.body.insertAdjacentHTML('beforeEnd','<IMG ID='+myid+' CLASS=dd_spawned SRC=' + img.src + '>');
		document.body.insertAdjacentHTML('beforeEnd','<IMG ID='+myid+'.ddshadow CLASS=dd_spawned SRC=' + img.src + '>');
	}
	else 
	{
		//alert('You need a DOM compatible browser like IE6 NS7 OP7 MOZ1.5.');
		return false;
	}
	
	alert('Created the html node...');

	return dd_spawn_person(myid,mylook);
}
*/

function dd_spawn_person(myid,myanims,myname,myemail)
{
	
	//alert('dd_spawn_person('+myid+','+myanims+')');
	thisCBE = new CrossBrowserElement(myid,36,72);
	thisCBE.look = myanims;
	thisCBE.framenumba = 0;
	thisCBE.framecount = 6;
	thisCBE.xSpeed = 8;
	thisCBE.ySpeed = 4;
	
	thisCBE.timestamp = new Date();
	thisCBE.timestamp.getTime();

	thisCBE.ddclothing = new CrossBrowserElement(myid+'.ddclothing',36,72);
	thisCBE.ddclothing.framenumba = 0;
	thisCBE.ddclothing.framecount = 6;
	thisCBE.ddclothing.xSpeed = 8;
	thisCBE.ddclothing.ySpeed = 4;
	
	thisCBE.ddhat = new CrossBrowserElement(myid+'.ddhat',36,72);
	thisCBE.ddhat.xSpeed = 8;
	thisCBE.ddhat.ySpeed = 4;

	thisCBE.ddextra = new CrossBrowserElement(myid+'.ddextra',36,72);
	thisCBE.ddextra.xSpeed = 8;
	thisCBE.ddextra.ySpeed = 4;

	thisCBE.ddshadow = new CrossBrowserElement(myid+'.ddshadow',32,32);
	thisCBE.ddshadow.xSpeed = 8;
	thisCBE.ddshadow.ySpeed = 4;
	
	thisCBE.ddnametag = new CrossBrowserElement(myid+'.ddnametag',128,12);
	thisCBE.ddnametag.xSpeed = 8;
	thisCBE.ddnametag.ySpeed = 4;
	
	if (myid=='Player0')
		thisCBE.ddbubba = new CrossBrowserElement(myid+'.ddbubba',190,158); // NPC big bubble
	else
		thisCBE.ddbubba = new CrossBrowserElement(myid+'.ddbubba',190,94);
	thisCBE.ddbubba.xSpeed = 8;
	thisCBE.ddbubba.ySpeed = 4;
	
	if ((thisCBE.ddnametag) && (thisCBE.ddnametag.ele))
	{
		if (myname)
		{
			thisCBE.ddnametag.ele.innerHTML = myname;
		}
		else
		{
			thisCBE.ddnametag.ele.innerHTML = myid;
		}
	}

	if (myname) 
	{
		//spawnx = 384;
		//spawny = 384;
		if (myemail=='wildbill_NPC') // NPC
		{
			//spawnx = grid_to_pixelX(10,12); // saloon door
			//spawny = grid_to_pixelY(10,12);
			spawnx = grid_to_pixelX(3,17); // saloon door
			spawny = grid_to_pixelY(3,17);
		}
		else if (myemail=='silverado_NPC') // NPC
		{
			spawnx = grid_to_pixelX(5,18);
			spawny = grid_to_pixelY(5,18);
		}
		else if (myemail=='bartender_NPC') // NPC
		{
			spawnx = grid_to_pixelX(3,26);
			spawny = grid_to_pixelY(3,26);
		}
		else if (myemail=='calamity_NPC') // NPC
		{
			spawnx = grid_to_pixelX(3,13);
			spawny = grid_to_pixelY(3,13);
		}
		else if (myemail=='pcj_NPC') // NPC
		{
			spawnx = grid_to_pixelX(8,16);
			spawny = grid_to_pixelY(8,16);
		}
		else // all other players: spawn corner
		{
			// check dd_alt and dd_img and maybe start elsewhere
			if (dd_can_stand(dd_spawn_gx,dd_spawn_gy))
			{
				spawnx = grid_to_pixelX(dd_spawn_gx,dd_spawn_gy);
				spawny = grid_to_pixelY(dd_spawn_gx,dd_spawn_gy);
			}
			else
			{	// force middle of the screen
				if (dd_v2_debug) alert('DEBUG: spawn location is inside a wall - using center.');
				spawnx = grid_to_pixelX(8,20);
				spawny = grid_to_pixelY(8,20);
			}
			
			
		}
		thisCBE.playername = myname;
	}
	else
	{
		// bottom middle
		spawnx = grid_to_pixelX(8,30);
		spawny = grid_to_pixelY(8,30);
		thisCBE.playername = '';
	}

	if (myemail)
		thisCBE.playeremail = myemail;
	else
		thisCBE.playeremail = '';

	if (!myanims)
	{
		// hidden FOR NOW - unused players!
		spawnx = -96;
		spawny = 600;
	}
	
	spawnx += AVATAR_X_NUDGE;
	spawny += AVATAR_Y_NUDGE;

	// store for dd_look_at()
	thisCBE.gridX = pixel_to_gridX(spawnx,spawny);
	thisCBE.gridY = pixel_to_gridY(spawnx,spawny);
	
	if (thisCBE) // starting positions
	{
		thisCBE.moveTo(spawnx,spawny);
		thisCBE.show();

		thisCBE.ddclothing.moveTo(spawnx,spawny);
		thisCBE.ddclothing.show();

		thisCBE.ddhat.moveTo(spawnx,spawny);
		thisCBE.ddhat.show();

		thisCBE.ddextra.moveTo(spawnx,spawny);
		thisCBE.ddextra.show();

		thisCBE.ddshadow.moveTo(spawnx,spawny+thisCBE.height-22);
		thisCBE.ddshadow.show();

		thisCBE.ddnametag.moveTo(spawnx-48,spawny+thisCBE.height);
		thisCBE.ddnametag.show();
	}

	if (myanims)
	{
		thisCBE.dd_preload_all_frames(myanims);
	}


	return thisCBE;
}

function dd_init()
{
	
	if (dd_v2_debug && document.chatform) document.chatform.mychat.value='DEBUG MODE - Initializing...';

	//if (dd_v2_debug) debug_images();

	// grab mouse move event - this lowers the framerate a LOT on old browsers
	if (navigator.appName == 'Netscape') { document.captureEvents(Event.MOUSEMOVE); document.onmousemove = netscapeMouseMove; } 
	else { document.onmousemove = microsoftMouseMove; }

	// grab mouse click event
	if (navigator.appName == 'Netscape') { document.captureEvents(Event.CLICK); document.onclick = netscapeMouseClick; } 
	else { document.onclick = microsoftMouseClick; }

	window_journal = new CrossBrowserElement('window_journal', 374, 411);
	window_journal.xSpeed = .2;
	window_journal.ySpeed = .2;
	window_journal.moveTo(0,-1000);
	window_journal.dd_dont_slow_down = false;

	window_map = new CrossBrowserElement('window_map', 308, 440); //old: 288, 400);
	window_map.xSpeed = .2;
	window_map.ySpeed = .2;
	window_map.moveTo(0,-1000);
	window_map.dd_dont_slow_down = false;

	window_history = new CrossBrowserElement('window_history', 359, 386);
	window_history.xSpeed = .2;
	window_history.ySpeed = .2;
	window_history.moveTo(0,-1000);
	window_history.dd_dont_slow_down = false;
	//window_history.addEventListener('drag'); // draggable!

	window_slots = new CrossBrowserElement('window_slots', 252, 420);
	window_slots.xSpeed = .2;
	window_slots.ySpeed = .2;
	window_slots.moveTo(0,-1000);
	window_slots.dd_dont_slow_down = false;
	window_slots.hide();

	//window_blackjack = new CrossBrowserElement('window_blackjack', 400, 320);
	window_blackjack = new CrossBrowserElement('window_blackjack', 720, 444);
	window_blackjack.xSpeed = .2;
	window_blackjack.ySpeed = .2;
	window_blackjack.moveTo(0,-1000);
	window_blackjack.dd_dont_slow_down = false;
	window_blackjack.hide();

	window_inventory = new CrossBrowserElement('window_inventory', 350, 277);
	window_inventory.xSpeed = .2;
	window_inventory.ySpeed = .2;
	window_inventory.moveTo(0,-1000);
	window_inventory.dd_dont_slow_down = false;

	window_shootout = new CrossBrowserElement('window_shootout', 720, 36);
	window_shootout.xSpeed = .2;
	window_shootout.ySpeed = .2;
	window_shootout.moveTo(0,-1000);
	window_shootout.dd_dont_slow_down = false;
	window_shootout.hide();
	
	window_shootout = new CrossBrowserElement('window_shootout', 720, 36);
	window_shootout.xSpeed = .2;
	window_shootout.ySpeed = .2;
	window_shootout.moveTo(0,-1000);
	window_shootout.dd_dont_slow_down = false;
	window_shootout.hide();

	window_shootout_ready = new CrossBrowserElement('window_shootout_ready', 348, 134);
	window_shootout_ready.moveTo(0,-1000);
	window_shootout_ready.hide();

	window_shootout_gameover = new CrossBrowserElement('window_shootout_gameover', 348, 134);
	window_shootout_gameover.moveTo(0,-1000);
	window_shootout_gameover.hide();
	

	// NEW WAY USES 6 frame animation and less spam
	dd_people[1] = Player1 = dd_spawn_person('Player1',playeravatar,playername,playeremail);
	dd_people[1].playername = playername;
	dd_people[1].playeremail = playeremail;
	
	// walk debug - grid cursor
	if (dd_v2_debug)
	{
	gcursor = new CrossBrowserElement('gcursor',48,24); //, " . 48 * $dd['spritescale'] . ", " . 24 * $dd['spritescale'] . "); // id, width, height
	gcursor.moveTo(320,256);
	gcursor.xSpeed = .3;
	gcursor.ySpeed = .3;
	gcursor.show();
	}



	var there_is_an_NPC = true; // default
	var NPC_walks_around = true;
	if ((map=='000_shoot') || (map == 'gem_shootout1_flipped')) // Shootout wildbill
	{
		NPC_walks_around = false;
		
		// with Wild Bill watching you and introducing the fight
		//dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0','wildbill', '<font color=yellow>Wild Bill SHOOTOUT</font>','wildbill_NPC'); // NPC

		// without bot:
		dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0'); //,'pcj', 'Potato Creek Johnny');
		there_is_an_NPC = false;

		// crosshairs!
		xcursor = new CrossBrowserElement('xcursor',72,72); //, " . 48 * $dd['spritescale'] . ", " . 24 * $dd['spritescale'] . "); // id, width, height
		xcursor.moveTo(320,256);
		xcursor.xSpeed = .3;
		xcursor.ySpeed = .3;
		xcursor.show();
		
		var bloop=0;
		// shootout holes
		for (bloop=1; (bloop < maxbulletholes+1); bloop++)
		{
			bullethole[bloop] = new CrossBrowserElement('bullethole'+bloop,8,8);
		}
		// shootout badguys and the targets you click
		for (bloop=1; (bloop < maxbadguys+1); bloop++)
		{
			/*
			targx = 48*2*bloop;
			targy = 48*bloop;
			if (bloop==1) targx -= 48;
			if (bloop==2) targx += 48*4;
			if (bloop==4) targx += 48*4;
			if (bloop==5) targx -= 48*3;
			if (bloop==6) targx -= 48*9;
			*/
			dd_people_shootout[bloop] = new CrossBrowserElement('Shooter'+bloop); //,72,72);
			dd_people_shootout[bloop].idleframes = 0;
			//dd_people_shootout[bloop].moveTo(targx,targy);
			dd_people_shootout[bloop].show();
			dd_people_shootout[bloop].targetgif = new CrossBrowserElement('Target'+bloop);//,72,72);
			//dd_people_shootout[bloop].targetgif.moveTo(targx,targy);
			dd_people_shootout[bloop].targetgif.show();
		}
		dd_open_window(window_shootout);
		dd_open_window(window_shootout_ready); // shootout: fixme: one then the other
		sfxreload();
		//shootout_ai();		
	}
	else if (map=='mm_flipped')  // NPC wildbill
	{
		dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0','wildbill', '<font color=yellow>Wild Bill Hickok</font>','wildbill_NPC'); // NPC
	}
	else if (map=='saloon10_flipped') // NPC bartender
	{
		//dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0','male1,gambler1,malehair2', '<font color=yellow>Bartender</font>','bartender_NPC'); // NPC
		dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0','s10bar1', '<font color=yellow>The Bartender</font>','bartender_NPC'); // NPC
	}
	else if (map=='int_silver_flipped') // NPC silverado NPC
	{
		dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0','silversg1', '<font color=yellow>Silver A. Doe</font>','silverado_NPC'); // NPC
	}
	else if (map=='611_main_e_flipped') // NPC calamity
	{
		dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0','calamity', '<font color=yellow>Calamity Jane</font>','calamity_NPC'); // NPC
	}
	else if (map=='700_main_w') // NPC pcj
	{
		dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0','pcj', '<font color=yellow>Potato Creek Johnny</font>','pcj_NPC'); // NPC
	}
	else
	{	// without bot:
		dd_people[NPCSLOT] = Player0 = dd_spawn_person('Player0'); //,'pcj', 'Potato Creek Johnny');
		there_is_an_NPC = false;
	}

	dd_people[2] = Player2 = dd_spawn_person('Player2');
	dd_people[3] = Player3 = dd_spawn_person('Player3');
	dd_people[4] = Player4 = dd_spawn_person('Player4');
	dd_people[5] = Player5 = dd_spawn_person('Player5');
	dd_people[6] = Player6 = dd_spawn_person('Player6');
	dd_people[7] = Player7 = dd_spawn_person('Player7');
	dd_people[8] = Player8 = dd_spawn_person('Player8');
	dd_people[9] = Player9 = dd_spawn_person('Player9');
	dd_people[10] = Player10 = dd_spawn_person('Player10');
	dd_people[11] = Player11 = dd_spawn_person('Player11');
	dd_people[12] = Player12 = dd_spawn_person('Player12');
	dd_people[13] = Player13 = dd_spawn_person('Player13');
	dd_people[14] = Player14 = dd_spawn_person('Player14');
	dd_people[15] = Player15 = dd_spawn_person('Player15');
	dd_people[16] = Player16 = dd_spawn_person('Player16');
	dd_people[17] = Player17 = dd_spawn_person('Player17');
	dd_people[18] = Player18 = dd_spawn_person('Player18');
	dd_people[19] = Player19 = dd_spawn_person('Player19');
	dd_people[20] = Player20 = dd_spawn_person('Player20');
	dd_people_count = 20;
	
	// word bubbles for chatter
	bub0 = new CrossBrowserElement('Player0.ddbubba',190,158); // NPC big bubble
	bub1 = new CrossBrowserElement('Player1.ddbubba',190,94);
	bub2 = new CrossBrowserElement('Player2.ddbubba',190,94);
	bub3 = new CrossBrowserElement('Player3.ddbubba',190,94);
	bub4 = new CrossBrowserElement('Player4.ddbubba',190,94);
	bub5 = new CrossBrowserElement('Player5.ddbubba',190,94);
	bub6 = new CrossBrowserElement('Player6.ddbubba',190,94);
	bub7 = new CrossBrowserElement('Player7.ddbubba',190,94);
	bub8 = new CrossBrowserElement('Player8.ddbubba',190,94);
	bub9 = new CrossBrowserElement('Player9.ddbubba',190,94);
	bub10 = new CrossBrowserElement('Player10.ddbubba',190,94);
	bub11 = new CrossBrowserElement('Player11.ddbubba',190,94);
	bub12 = new CrossBrowserElement('Player12.ddbubba',190,94);
	bub13 = new CrossBrowserElement('Player13.ddbubba',190,94);
	bub14 = new CrossBrowserElement('Player14.ddbubba',190,94);
	bub15 = new CrossBrowserElement('Player15.ddbubba',190,94);
	bub16 = new CrossBrowserElement('Player16.ddbubba',190,94);
	bub17 = new CrossBrowserElement('Player17.ddbubba',190,94);
	bub18 = new CrossBrowserElement('Player18.ddbubba',190,94);
	bub19 = new CrossBrowserElement('Player19.ddbubba',190,94);
	bub20 = new CrossBrowserElement('Player20.ddbubba',190,94);
	
	//alert('Completed all inits.  Starting timers...');
	// _NPC // NPC map? turn on NPCchat.
	if (there_is_an_NPC) // NPC maps
	{
		if (NPC_walks_around) dd_ai_tick(); // NPC
		NPCchat(0);
	}
	
	if (destroy_idle_bots) 
		setTimeout('dd_destroy_idle_players()',check_idle_time);

	// now we can fiddle with settings
	dd_mute_music(true);
	// start chat refresh cycle
	dd_mute_chat(true); 	//if (dd_chat_on) listen_to_chats(); //setTimeout('listen_to_chats()',4444);
	// start realtime NPC ai
	
	//$CK speed up load time: cached images only... lame mouseovers!
	// already run //dd_preload(); // GUI mouseovers in ram

	dd_refresh_inventory(); // update player_inventory in window

	//if (dd_v2_debug) alert('DEBUG: Init completed perfectly.\nGame engine is running!');
	if (dd_v2_debug) if (document.chatform) document.chatform.mychat.value='DEBUG MODE - Game Engine loaded OK.';


}



































// CrossBrowserElement Object Constructor:

function CrossBrowserElement(eleId, width, height)
{
  // $CK DigitalDeadwood upgrades
  this.dd_dont_slow_down = true; 	// no slow down at end of a move
  this.dd_walk_v2 = dd_walk_v2; 	// point to improved walk function
  this.dd_look_at = dd_look_at; 	// look at mouse XY
  this.dd_preload_all_frames = dd_preload_all_frames; // load 48 images!

  // Properties:
  this.id = eleId;
  this.ele = null;
  this.x = 0;
  this.y = 0;
  this.width = 0;
  this.height = 0;
  this.clipping = false;
  this.xMoving = false;
  this.yMoving = false;
  this.xTarget = 0;
  this.yTarget = 0;
  this.clipSpeed = 50;
  this.xSpeed = .5;
  this.ySpeed = .6;

  // Methods (high-level):
  this.setSize = cbeSetSize;
  this.moveTo = cbeMoveTo;
  this.moveToPos = cbeMoveToPos;
  this.moveBy = cbeMoveBy;
  this.slideTo = cbeSlideTo;
  this.slideToPos = cbeSlideToPos;
  this.slideToX = cbeSlideToX;
  this.slideToY = cbeSlideToY;
  this.scrollBy = cbeScrollBy;
  this.clipBy = cbeClipBy;
  this.autoClip = cbeAutoClip;
  this.getPos = cbeGetPos;

  // Methods (browser-specific):
  this.setLeft = domSetLeft;
  this.getLeft = domGetLeft;
  this.setTop = domSetTop;
  this.getTop = domGetTop;
  this.setZIndex = domSetZIndex;
  this.getZIndex = domGetZIndex;
  this.setWidth = domSetWidth;
  this.getWidth = domGetWidth;
  this.setHeight = domSetHeight;
  this.getHeight = domGetHeight;
  this.setClip = domSetClip;
  this.getClip = domGetClip;
  this.getClipTop = domGetClipTop;
  this.getClipRight = domGetClipRight;
  this.getClipBottom = domGetClipBottom;
  this.getClipLeft = domGetClipLeft;
  this.getClipWidth = domGetClipWidth;
  this.getClipHeight = domGetClipHeight;
  this.getClipArray = domGetClipArray;
  this.show = domShow;
  this.hide = domHide;
  this.isVisible = domIsVisible;
  this.setHtml = domSetHtml;
  this.setBgColor = domSetBgColor;
  this.setBgImage = domSetBgImage;

  // Assign browser-specifics:

  if (document.getElementById) {
    this.ele = document.getElementById(eleId);
    if (is.opera) {
      this.setLeft = opSetLeft;
      this.getLeft = opGetLeft;
      this.setTop = opSetTop;
      this.getTop = opGetTop;
      this.setWidth = opSetWidth;
      this.setHeight = opSetHeight;
      this.setClip = 
      this.getClip = 
      this.getClipTop = 
      this.getClipRight = 
      this.getClipBottom = 
      this.getClipLeft = 
      this.getClipArray = returnZero;
      this.getClipWidth = domGetWidth;
      this.getClipHeight = domGetHeight;
      this.show = opShow;
      this.setHtml = returnZero;
      this.setBgColor = opSetBgColor;
      this.setBgImage = returnZero;
      
    }
  }
  else if (is.ie4up) {
    this.ele = document.all[eleId];
  }
  else if (is.nav4up) {
    this.ele = document.layers[eleId];
    this.setLeft = nnSetLeft;
    this.getLeft = nnGetLeft;
    this.setTop = nnSetTop;
    this.getTop = nnGetTop;
    this.setZIndex = nnSetZIndex;
    this.getZIndex = nnGetZIndex;
    this.setWidth = nnSetWidth;
    this.getWidth = nnGetWidth;
    this.setHeight = nnSetHeight;
    this.getHeight = nnGetHeight;
    this.setClip = nnSetClip;
    this.getClip = nnGetClip;
    this.getClipTop = nnGetClipTop;
    this.getClipRight = nnGetClipRight;
    this.getClipBottom = nnGetClipBottom;
    this.getClipLeft = nnGetClipLeft;
    this.getClipWidth = nnGetClipWidth;
    this.getClipHeight = nnGetClipHeight;
    this.getClipArray = nnGetClipArray;
    this.show = nnShow;
    this.hide = nnHide;
    this.isVisible = nnIsVisible;
    this.setHtml = nnSetHtml;
    this.setBgColor = nnSetBgColor;
    this.setBgImage = nnSetBgImage;
  }
  else {
    alert("This javascript will not run on your browser!  To play the game, you simply need to upgrade your browser to a newer version.");
    return;
  }
  if (!this.ele) {
    if (dd_v2_debug) alert(eleId + " does not exist in this document.  Init failed.");
    return;
  }

  if (arguments.length > 1) {
    this.setSize(width, height);
    this.setClip(0, width , height , 0);
    this.moveTo(-width, -height);
    this.hide();
  }
}






function dd_preload_all_frames(animname)
{
	//alert('DEBUG: dd_preload_all_frames: '+animname);

	if (dd_v2_debug && document.chatform) document.chatform.mychat.value='DEBUG MODE - Loading avatar ' + animname;

	if (this.timestamp) this.timestamp.getTime(); // not idle now
	
	this.dd_frame = Array();
	this.dd_frame[dirUP] = Array();
	this.dd_frame[dirDN] = Array();
	this.dd_frame[dirLF] = Array();
	this.dd_frame[dirRT] = Array();
	this.dd_frame[dirUL] = Array();
	this.dd_frame[dirUR] = Array();
	this.dd_frame[dirDL] = Array();
	this.dd_frame[dirDR] = Array();
	
	this.dd_clothing = Array();
	this.dd_clothing[dirUP] = Array();
	this.dd_clothing[dirDN] = Array();
	this.dd_clothing[dirLF] = Array();
	this.dd_clothing[dirRT] = Array();
	this.dd_clothing[dirUL] = Array();
	this.dd_clothing[dirUR] = Array();
	this.dd_clothing[dirDL] = Array();
	this.dd_clothing[dirDR] = Array();
	
	this.dd_hat = Array();
	this.dd_extra = Array();
	

	// defaults for single layer avatar
	this.myskin = animname;
	this.myclothing = 0;
	this.myhat = 0;
	this.myextra = 0;
	baseFN = 'walk_';
	base_anim_FN = 'walk_';
	framecount = 6;
	
	if (string_contains(animname,',')) // multi layer avatar!
	{
		//alert('DEBUG: multi-layer avatar: '+animname);
		aa = animname.split(',');
		this.myskin = aa[0];
		this.myclothing = aa[1];
		this.myhat = aa[2];
		this.myextra = aa[3];
		baseFN = 'a_';
		base_anim_FN = 'a_';
	}
	
	// in a shootout we need the 72px avatars
	if ((map=='000_shoot') || (map == 'gem_shootout1_flipped')) // Shootout
	{
		this.setSize(72,72);
		this.setClip(0,72,72,0);
		this.moveBy(-18,0);
		this.ddclothing.setSize(72,72); 
		this.ddclothing.setClip(0,72,72,0);
		this.ddclothing.moveBy(-18,0);
		baseFN = 'a_';
		base_anim_FN = 'shooting_';
		framecount = 1;
	}	

	
	// draw first FRAME before loading the rest!
	framenumber=0; // dir=dn
	if ((this.myhat) && (this.ddhat)) 		{ this.ddhat.show(); this.ddhat.ele.src = 'cache.php?img='+baseFN+this.myhat+'_dn.gif'; }
	if ((this.myclothing) && (this.ddclothing)) 	{ this.ddclothing.show(); this.ddclothing.ele.src = 'cache.php?img='+base_anim_FN+this.myclothing+'_dn_'+framenumber+'.gif'; }
	if ((this.myskin) && (this.ele)) 		{ this.show(); this.ele.src = 'cache.php?img='+base_anim_FN+this.myskin+'_dn_'+framenumber+'.gif'; }
	if ((this.myextra) && (this.ddextra)) 		{ this.ddextra.show(); this.ddextra.ele.src = 'cache.php?img='+baseFN+this.myextra+'_dn.gif'; }
	
	if (this.ddshadow) this.ddshadow.show();
	if (this.ddnametag) this.ddnametag.show();
	//if (this.ddbubba) this.ddbubba.show();

	if (this.myhat) // hat/hair - one frame only
	{
		this.dd_hat[dirUP]=new Image(); this.dd_hat[dirUP].src='cache.php?img='+baseFN+this.myhat+'_up.gif';
		this.dd_hat[dirDN]=new Image(); this.dd_hat[dirDN].src='cache.php?img='+baseFN+this.myhat+'_dn.gif';
		this.dd_hat[dirLF]=new Image(); this.dd_hat[dirLF].src='cache.php?img='+baseFN+this.myhat+'_lf.gif';
		this.dd_hat[dirRT]=new Image(); this.dd_hat[dirRT].src='cache.php?img='+baseFN+this.myhat+'_rt.gif';
		this.dd_hat[dirUL]=new Image(); this.dd_hat[dirUL].src='cache.php?img='+baseFN+this.myhat+'_ul.gif';
		this.dd_hat[dirUR]=new Image(); this.dd_hat[dirUR].src='cache.php?img='+baseFN+this.myhat+'_ur.gif';
		this.dd_hat[dirDL]=new Image(); this.dd_hat[dirDL].src='cache.php?img='+baseFN+this.myhat+'_dl.gif';
		this.dd_hat[dirDR]=new Image(); this.dd_hat[dirDR].src='cache.php?img='+baseFN+this.myhat+'_dr.gif';
	}

	if (this.myextra) // extra - one frame only
	{
		this.dd_extra[dirUP]=new Image(); this.dd_extra[dirUP].src='cache.php?img='+baseFN+this.myextra+'_up.gif';
		this.dd_extra[dirDN]=new Image(); this.dd_extra[dirDN].src='cache.php?img='+baseFN+this.myextra+'_dn.gif';
		this.dd_extra[dirLF]=new Image(); this.dd_extra[dirLF].src='cache.php?img='+baseFN+this.myextra+'_lf.gif';
		this.dd_extra[dirRT]=new Image(); this.dd_extra[dirRT].src='cache.php?img='+baseFN+this.myextra+'_rt.gif';
		this.dd_extra[dirUL]=new Image(); this.dd_extra[dirUL].src='cache.php?img='+baseFN+this.myextra+'_ul.gif';
		this.dd_extra[dirUR]=new Image(); this.dd_extra[dirUR].src='cache.php?img='+baseFN+this.myextra+'_ur.gif';
		this.dd_extra[dirDL]=new Image(); this.dd_extra[dirDL].src='cache.php?img='+baseFN+this.myextra+'_dl.gif';
		this.dd_extra[dirDR]=new Image(); this.dd_extra[dirDR].src='cache.php?img='+baseFN+this.myextra+'_dr.gif';
	}

	for (loopa=0; loopa<framecount; loopa++) // 0 to 5 are the images... was <7
	{
		// 5 frames per anim! (frame 3 = frame 0)
		framenumber = loopa; if (loopa==3) framenumber = 0; 
		
		if (this.myclothing)
		{ 
		this.dd_clothing[dirUP][loopa]=new Image(); this.dd_clothing[dirUP][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_up_'+framenumber+'.gif';
		this.dd_clothing[dirDN][loopa]=new Image(); this.dd_clothing[dirDN][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_dn_'+framenumber+'.gif';
		this.dd_clothing[dirLF][loopa]=new Image(); this.dd_clothing[dirLF][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_lf_'+framenumber+'.gif';
		this.dd_clothing[dirRT][loopa]=new Image(); this.dd_clothing[dirRT][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_rt_'+framenumber+'.gif';
		this.dd_clothing[dirUL][loopa]=new Image(); this.dd_clothing[dirUL][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_ul_'+framenumber+'.gif';
		this.dd_clothing[dirUR][loopa]=new Image(); this.dd_clothing[dirUR][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_ur_'+framenumber+'.gif';
		this.dd_clothing[dirDL][loopa]=new Image(); this.dd_clothing[dirDL][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_dl_'+framenumber+'.gif';
		this.dd_clothing[dirDR][loopa]=new Image(); this.dd_clothing[dirDR][loopa].src='cache.php?img='+base_anim_FN+this.myclothing+'_dr_'+framenumber+'.gif';
		}

		// skin
		this.dd_frame[dirUP][loopa]=new Image(); this.dd_frame[dirUP][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_up_'+framenumber+'.gif';
		this.dd_frame[dirDN][loopa]=new Image(); this.dd_frame[dirDN][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_dn_'+framenumber+'.gif';
		this.dd_frame[dirLF][loopa]=new Image(); this.dd_frame[dirLF][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_lf_'+framenumber+'.gif';
		this.dd_frame[dirRT][loopa]=new Image(); this.dd_frame[dirRT][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_rt_'+framenumber+'.gif';
		this.dd_frame[dirUL][loopa]=new Image(); this.dd_frame[dirUL][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_ul_'+framenumber+'.gif';
		this.dd_frame[dirUR][loopa]=new Image(); this.dd_frame[dirUR][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_ur_'+framenumber+'.gif';
		this.dd_frame[dirDL][loopa]=new Image(); this.dd_frame[dirDL][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_dl_'+framenumber+'.gif';
		this.dd_frame[dirDR][loopa]=new Image(); this.dd_frame[dirDR][loopa].src='cache.php?img='+base_anim_FN+this.myskin+'_dr_'+framenumber+'.gif';

	}
	
}


var last_direction = 0;
function dd_look_at(direction) 	// DD: face this pixel location
{
	if (!dd_loaded) return;
	if (!direction) return;

	if (last_direction == direction) return;


	if (dd_v2_debug) dd_debugme('dd_look_at '+direction);

	if ((this.ele.src) && (this.dd_frame) && (this.dd_frame[direction]) && (this.dd_frame[direction][0])) this.ele.src = this.dd_frame[direction][0].src;
	if ((this.ddclothing) && (this.ddclothing.ele.src) && (this.dd_clothing) && (this.dd_clothing[direction]) && (this.dd_clothing[direction][0])) this.ddclothing.ele.src = this.dd_clothing[direction][0].src;
	if ((this.ddhat) && (this.ddhat.ele.src) && (this.dd_hat) && (this.dd_hat[direction])) this.ddhat.ele.src = this.dd_hat[direction].src;
	if ((this.ddextra) && (this.ddextra.ele.src) && (this.dd_extra) && (this.dd_extra[direction])) this.ddextra.ele.src = this.dd_extra[direction].src;

	last_direction = direction;
}

function dd_walk_v2(direction,count) 	// DD: proper walk function!
{
	
	if (!dd_loaded) return;
	
	var dd_frames_per_square = 6;		// two steps
	var dd_ms_per_frame = 60; 		// 0.06 seconds
	var movescale = 1;

	if (this==Player0) // NPC in slot 99 player0
	{
		dd_frames_per_square = 24; // eight steps on ice
		dd_ms_per_frame = 60; // high fps = less movement...
		movescale=0.25; // quarter speed
	}

	if (!direction) return;
	//if (!this.dd_frame) { alert(this.id + ' has no frames!');  }
	//if (count==dd_frames_per_square) alert(this.id + '.dd_walk_v2 starting a move: ' + direction);

	currentX = this.getLeft();
	currentY = this.getTop();

	var newX = currentX;
	var newY = currentY;
	
	if (direction==dirUP)
	{
		newY = currentY - (this.ySpeed*movescale);
	}
	else if (direction==dirDN)
	{
		newY = currentY + (this.ySpeed*movescale);
	}
	else if (direction==dirLF)
	{
		newX = currentX - (this.xSpeed*movescale);
	}
	else if (direction==dirRT)
	{
		newX = currentX + (this.xSpeed*movescale);
	}
	else if (direction==dirUR)
	{
		newY = currentY - (this.ySpeed*movescale*0.5);
		newX = currentX + (this.xSpeed*movescale*0.5);
	}
	else if (direction==dirUL)
	{
		newY = currentY - (this.ySpeed*movescale*0.5);
		newX = currentX - (this.xSpeed*movescale*0.5);
	}
	else if (direction==dirDR)
	{
		newY = currentY + (this.ySpeed*movescale*0.5);
		newX = currentX + (this.xSpeed*movescale*0.5);
	}
	else if (direction==dirDL)
	{
		newY = currentY + (this.ySpeed*movescale*0.5);
		newX = currentX - (this.xSpeed*movescale*0.5);
	}
	else
	{
		newY = currentY;
		newX = currentX;
	}

	//this.setLeft(newX);this.setTop(newY);

	/*
	// take target z-index each anim step
	targetgridy = pixel_to_gridX(newX,newY);
	targetgridx = pixel_to_gridY(newX,newY);
	newZ = dd_zin[targetgridy][targetgridx];
	if (newZ) 
	{
		thisperson.setZIndex(newZ); 
		if (thisperson.ddclothing) thisperson.ddclothing.setZIndex(newZ+1);
		if (thisperson.ddhat) thisperson.ddhat.setZIndex(newZ+2);
		if (thisperson.ddextra) thisperson.ddextra.setZIndex(newZ+3);
	}
	*/

	this.moveTo(newX,newY);
	
	if (this.ddshadow)
	{
		//this.ddshadow.setLeft(newX); this.ddshadow.setTop(newY+this.height-22);
		this.ddshadow.moveTo(newX,newY+this.height-22);
	}
	
	if (this.ddclothing)	// FIXME: multi animate!
	{
		//this.ddclothing.setLeft(newX); this.ddclothing.setTop(newY);
		this.ddclothing.moveTo(newX,newY);
	}

	if (this.ddhat)
	{
		//this.ddhat.setLeft(newX); this.ddhat.setTop(newY);
		this.ddhat.moveTo(newX,newY);
		if ((this.ddhat.ele.src) && (this.dd_hat) && (this.dd_hat[direction])) this.ddhat.ele.src = this.dd_hat[direction].src;
	}

	if (this.ddextra)
	{
		//this.ddextra.setLeft(newX); this.ddextra.setTop(newY);
		this.ddextra.moveTo(newX,newY);
		if ((this.ddextra.ele.src) && (this.dd_extra) && (this.dd_extra[direction])) this.ddextra.ele.src = this.dd_extra[direction].src;
	}

	if (this.ddnametag)
	{
		this.ddnametag.moveTo(newX-48,newY+this.height);
	}

	if (this.ddbubba)
	{
		if (this==Player0) // NPC big bubble
			this.ddbubba.moveTo(newX,newY-72-64);//80-64);
		else
			this.ddbubba.moveTo(newX,newY-72);//80);
	}

	//targetgridx = pixel_to_gridX(newX,newY);
	//targetgridy = pixel_to_gridY(newX,newY);
	//this.setZIndex(dd_zin[targetgridy][targetgridx]);
	
	this.framenumba++; if (this.framenumba > this.framecount-1) this.framenumba = 0; // 0to5

	count--;
	
	if (count < 1)
	{
		//alert(this.id + ' is STOPPING.');
		if ((this.ele.src) && (this.dd_frame) && (this.dd_frame[direction]) && (this.dd_frame[direction][0])) this.ele.src = this.dd_frame[direction][0].src;
		if ((this.ddclothing) && (this.ddclothing.ele.src) && (this.dd_clothing) && (this.dd_clothing[direction]) && (this.dd_clothing[direction][0])) this.ddclothing.ele.src = this.dd_clothing[direction][0].src;
		return;
	}
	else
	{

		
		// 6 frame animation
		if ((this.ele.src) && (this.dd_frame))
		{
			if ((this.dd_frame[direction]) && (this.dd_frame[direction][this.framenumba])) //[count])
				this.ele.src = this.dd_frame[direction][this.framenumba].src;
			//else
			//	this.ele.src = this.dd_frame[direction][0].src; // ERROR!
				
			//DEBUG:

			//onlyfn=this.ele.src.substring(this.ele.src.lastIndexOf('/')+1)
			//if (this.id=='Player1') document.chatform.mychat.value = 'dir:'+direction+' frame:'+this.framenumba+' src:'+onlyfn;
		}
		

		// 6 frame animation
		if ((this.ddclothing) && (this.ddclothing.ele.src) && (this.dd_clothing))
		{
			if ((this.dd_clothing[direction]) && (this.dd_clothing[direction][this.framenumba]))
				this.ddclothing.ele.src = this.dd_clothing[direction][this.framenumba].src;
		}


		/*
		// looped anim gif old style
		if ((this.ele.src) && (this.dd_frame) && count==5)
		{
			this.ele.src = 'cache.php?img=fx_blank.gif'; // reset anim
			this.ele.src = 'this.dd_frame[direction][0].src';
		}
		*/

		
		//alert('Frame '+count+': '+this.id + '.ele.src='+this.ele.src);
		
		nextframeevent = this.id+'.dd_walk_v2('+direction+','+count+')';
		setTimeout(nextframeevent,dd_ms_per_frame);
	}

}

















// CrossBrowserElement Method Definitions:


// Move element to x,y position.

function cbeMoveTo(newX, newY)
{
  this.setLeft(newX);
  this.setTop(newY);
}


// Move element to logical position.

function cbeMoveToPos(pos, margin, outside)
{
  this.getPos(pos, margin, outside);
  this.setLeft(this.x);
  this.setTop(this.y);
}


// Get coordinates of logical position and assign to this.x and this.y

function cbeGetPos(pos, margin, outside)
{
  var x = this.getLeft();
  var y = this.getTop();
  var w = this.getClipWidth();
  var h = this.getClipHeight();
  var cw = getClientWidth();
  var ch = getClientHeight();
  var left = getScrollX();
  var top = getScrollY();
  var right = left + cw;
  var bottom = top + ch;
  var cenLeft = left + Math.floor(cw/2) - Math.floor(w/2);
  var cenTop = top + Math.floor(ch/2) - Math.floor(h/2);
  
  if (arguments.length > 1) {
    if (outside)
      margin = -margin;
    left += margin;
    top += margin;
    right -= margin;
    bottom -= margin;
  }

  switch (pos.toLowerCase()) {
    case 'center':
      x = cenLeft;
      y = cenTop;
      break;
    case 'centerH':
      x = cenLeft;
      break;
    case 'centerV':
      y = cenTop;
      break;  
    case 'n':
      if (outside) y = top - h;
      else y = top;
      break;
    case 'ne':
      if (outside) { x = right; y = top - h; }
      else { x = right - w; y = top; }
      break;
    case 'e':
      if (outside) x = right;
      else x = right - w;
      break;
    case 'se':
      if (outside) { x = right; y = bottom; }
      else { x = right - w; y = bottom - h }
      break;
    case 's':
      if (outside) y = top - h;
      else y = bottom - h;
      break;
    case 'sw':
      if (outside) { x = left - w; y = bottom; }
      else { x = left; y = bottom - h; }
      break;
    case 'w':
      if (outside) x = left - w;
      else x = left;
      break;
    case 'nw':
      if (outside) { x = left - w; y = top - h; }
      else { x = left; y = top; }
      break;
    default:
      alert("invalid 'pos' argument in getPos()");
  }
  this.x = x;
  this.y = y;
}


// Move element with respect to current position.

function cbeMoveBy(dX, dY)
{
  if (dX)
    this.setLeft(this.getLeft() + dX);
  if (dY)
    this.setTop(this.getTop() + dY);
}


// Set element's x position.

function domSetLeft(newX)
{
  //if (typeof(this.ele.style.left) != undefined) // $CK sanity
  this.ele.style.left = newX + "px";
}

function nnSetLeft(newX)
{
  this.ele.left = newX;
}

function opSetLeft(newX)
{
  this.ele.style.pixelLeft = newX;
}


// Set element's y position.

function domSetTop(newY)
{
  //if (typeof(this.ele.style.top) != undefined) // $CK sanity
  this.ele.style.top = newY + "px";
}

function nnSetTop(newY)
{
  this.ele.top = newY;
}

function opSetTop(newY)
{
  this.ele.style.pixelTop = newY;
}


// Get element's current x position.

function domGetLeft()
{
  return parseInt(this.ele.style.left);
}

function nnGetLeft()
{
  return this.ele.left;
}


function opGetLeft()
{
  return this.ele.style.pixelLeft;
}


// Get element's current y position.

function domGetTop()
{
  return parseInt(this.ele.style.top);
}

function nnGetTop()
{
  return this.ele.top;
}

function opGetTop()
{
  return this.ele.style.pixelTop;
}


// Set the element's z index.

function domSetZIndex(newZ)
{
  this.ele.style.zIndex = newZ;
}

function nnSetZIndex(newZ)
{
  this.ele.zIndex = newZ;
}


// Get the element's z index.

function domGetZIndex()
{
  return this.ele.style.zIndex;
}

function nnGetZIndex()
{
  return this.ele.zIndex;
}


// Set element's width and height.

function cbeSetSize(newWidth, newHeight)
{
  this.setWidth(newWidth);
  this.setHeight(newHeight);
}


// Set element's width.

function domSetWidth(newWidth)
{
  //if (dd_v2_debug) alert('DEBUG: domSetWidth('+newWidth+'): this.id=' + this.id);
  this.width = newWidth;
  //if (!this.ele.style) alert('DEBUG: (!this.ele.style): this.id=' + this.id);
  //if (!this.ele.style.width) alert('DEBUG: (!this.ele.style.width): this.id=' + this.id);
  //if (typeof(this.ele.style.width) != undefined) // IE 6 errors sometimes on next line why?
  	this.ele.style.width = newWidth + "px";
}

function nnSetWidth(newWidth)
{
  this.width = newWidth;
}

function opSetWidth(newWidth)
{
  this.width = newWidth;
  this.ele.style.pixelWidth = newWidth;
}


// Set element's height.

function domSetHeight(newHeight)
{
  this.height = newHeight;
  //if (typeof(this.ele.style.height) != undefined) // IE 6 errors sometimes
  this.ele.style.height = newHeight + "px";
}

function nnSetHeight(newHeight)
{
  this.height = newHeight;
}

function opSetHeight(newHeight)
{
  this.height = newHeight;
  this.ele.style.pixelHeight = newHeight;
}


// Get element's width.

function domGetWidth()
{
  return this.width;
}

function nnGetWidth()
{
  return this.width;
}


// Get element's height.

function domGetHeight()
{
  return this.height;
}

function nnGetHeight()
{
  return this.height;
}


// Show the element.

function domShow()
{
  this.ele.style.visibility = 'inherit';
}

function nnShow()
{
  this.ele.visibility = 'inherit';
}

function opShow()
{
  this.ele.style.visibility = 'visible';
}


// Hide the element.

function domHide()
{
  this.ele.style.visibility = 'hidden';
}

function nnHide()
{
  this.ele.visibility = 'hide';
}


// Return true if the element is visible (or vis is inherited), else false.

function domIsVisible()
{
  return (
    this.ele.style.visibility == 'visible'
    || this.ele.style.visibility == 'inherit'
    || this.ele.style.visibility == ''
  );
}

function nnIsVisible()
{
  return (
    this.ele.visibility == 'show'
    || this.ele.visibility == 'inherit'
    || this.ele.visibility == ''
  );
}


// Set the element's innerHTML.

function domSetHtml(newHtml)
{
  this.ele.innerHTML = newHtml;
}

function nnSetHtml(newHtml)
{
  if (newHtml == '') newHtml = ' ';
  this.ele.document.open();
  this.ele.document.write(newHtml);
  this.ele.document.close();
}


// Set the element's background color.

function domSetBgColor(newBgColor)
{
  if (newBgColor == null || newBgColor == 'transparent')
    newBgColor = null;
  this.ele.style.backgroundColor = newBgColor;
}

function nnSetBgColor(newBgColor)
{
  if (newBgColor == null || newBgColor == 'transparent')
    newBgColor = null;
  this.ele.bgColor = newBgColor;
}

function opSetBgColor(newBgColor)
{
  this.ele.style.background = newBgColor;
}


// Set the element's background image.

function domSetBgImage(newBgImage)
{
  this.ele.style.backgroundImage = "url(" + newBgImage + ")";
}

function nnSetBgImage(newBgImage)
{
  this.ele.background.src = newBgImage || null;
}


// Slide element to x,y position.

function cbeSlideTo(newXTarget, newYTarget)
{

  if (this.anim_walk_E) this.ele.src=this.anim_walk_E.src; // $CK walk anim

  if ( newXTarget != null)
    this.slideToX(newXTarget);
  if ( newYTarget != null)
    this.slideToY(newYTarget);
}


// Slide element to logical position.

function cbeSlideToPos(pos, margin, outside)
{
  this.getPos(pos, margin, outside);
  this.slideToX(this.x);
  this.slideToY(this.y);
}


// Slide element to x position.
// assumes id == object variable name

function cbeSlideToX(newXTarget, iterating)
{
  var delta, currentX;

  if (!this.xMoving) {
    this.xTarget = newXTarget;
  }
  else if (!iterating) {
    this.xTarget = newXTarget;
    return;
  }
  currentX = this.getLeft();
  this.xMoving = true;
  if (this.xSpeed < 1) {
    	
    	if (this.dd_dont_slow_down) // $CK
    	{	// $CK constant speed
    		delta = this.xSpeed;
	}
	else
	{	// $CK decelerate
    		delta = this.xSpeed * Math.abs(Math.abs(currentX) - Math.abs(this.xTarget));
    	}
    	
    	if (delta < 1) delta = 1;
  }
  else
    delta = this.xSpeed;

  if (currentX < this.xTarget) {
    if (currentX + delta <= this.xTarget)
      this.setLeft(currentX + delta);
    else
      this.setLeft(this.xTarget);
  }
  else if (currentX > this.xTarget) {
    if (currentX - delta >= this.xTarget)
      this.setLeft(currentX - delta);
    else
      this.setLeft(this.xTarget);
  }
  else 
  {
    this.xMoving = false;
    if (this.anim_stand_E) this.ele.src=this.anim_stand_E.src; // $CK dd stop animating walk
    return;
  }
  setTimeout(this.id+".slideToX("+this.xTarget+","+true+")",60);//25); // FPS
}


// Slide element to y position.
// assumes id == object variable name

function cbeSlideToY(newYTarget, iterating)
{
  var delta, currentY;

  if (!this.yMoving) {
    this.yTarget = newYTarget;
  }
  else if (!iterating) {
    this.yTarget = newYTarget;
    return;
  }
  currentY = this.getTop();
  this.yMoving = true;
  if (this.ySpeed < 1) {

    	if (this.dd_dont_slow_down) // $CK
    	{	// $CK constant speed
    		delta = this.ySpeed;
	}
	else
	{	// $CK decelerate
	    	delta = this.ySpeed * Math.abs(Math.abs(currentY) - Math.abs(this.yTarget));
    	}

	if (delta < 1) delta = 1;
  }
  else
    delta = this.ySpeed;

  if (currentY < this.yTarget) {
    if (currentY + delta <= this.yTarget)
      this.setTop(currentY + delta);
    else
      this.setTop(this.yTarget);
  }
  else if (currentY > this.yTarget) {
    if (currentY - delta >= this.yTarget)
      this.setTop(currentY - delta);
    else
      this.setTop(this.yTarget);
  }
  else 
  {
    this.yMoving = false;
    if (this.anim_stand_N) this.ele.src=this.anim_stand_N.src; // $CK dd stop animating walk
    return;
  }
  setTimeout(this.id+".slideToY("+this.yTarget+","+true+")",60);// FPS 25);
}


//

function returnZero()
{
  return 0;
}


// Set the clipping region.

function domSetClip(top, right, bottom, left)
{
  var clipRect =
    "rect("
    + top + "px "
    + right + "px "
    + bottom + "px "
    + left + "px"
    + ")";

  this.ele.style.clip = clipRect;
}


function nnSetClip(top, right, bottom, left)
{
  this.ele.clip.top = top;
  this.ele.clip.right = right;
  this.ele.clip.bottom = bottom;
  this.ele.clip.left = left;
}


// Get the clipping region as the css clip value (a string).

function domGetClip() {
  return this.ele.style.clip;
}

function nnGetClip()
{
  var clipRect =
    "rect("
    + this.ele.clip.top + "px "
    + this.ele.clip.right + "px "
    + this.ele.clip.bottom + "px "
    + this.ele.clip.left + "px"
    + ")";
  return clipRect;
}


// Get the clipping region as an array of individual values.
// a[1]==top, a[2]==right, a[3]==bottom, a[4]==left

function domGetClipArray()
{
  var re = /\(|px,?\s?\)?/;
  return this.ele.style.clip.split(re);
}

function nnGetClipArray()
{
  alert('method not implemented for NN4');
}


// Get individual clipping region values.

function domGetClipTop()
{
  var a = this.getClipArray();
  return parseInt(a[1]);
}

function nnGetClipTop()
{
  return this.ele.clip.top;
}
//--
function domGetClipRight()
{
  var a = this.getClipArray();
  return parseInt(a[2]);
}

function nnGetClipRight()
{
  return this.ele.clip.right;
}
//--
function domGetClipBottom()
{
  var a = this.getClipArray();
  return parseInt(a[3]);
}

function nnGetClipBottom()
{
  return this.ele.clip.bottom;
}
//--
function domGetClipLeft()
{
  var a = this.getClipArray();
  return parseInt(a[4]);
}

function nnGetClipLeft()
{
  return this.ele.clip.left;
}


// Get clipping region width and height.

function domGetClipWidth()
{
  var a = this.getClipArray();
  return (a[2] - a[4]);
}

function nnGetClipWidth()
{
  return this.ele.clip.width;
}

function domGetClipHeight()
{
  var a = this.getClipArray();
  return (a[3] - a[1]);
}

function nnGetClipHeight()
{
  return this.ele.clip.height;
}


// If cmd=='clip', clip edge until clip coords==0.
// If cmd=='unclip', unclip edge until coords reach element dimensions.

function cbeAutoClip(edge, cmd, dt, dr, db, dl)
{
  if (arguments.length == 2) {
    if (this.clipping) return;
    else this.clipping = true;
    var unclip = true;
    var w = this.getWidth();
    var h = this.getHeight();
    var xcs = Math.abs(this.clipSpeed);
    var ycs = xcs;
    // Get x and y speeds that are proportional
    // to the element's width and height
    if (h > w) {
      ycs *= (h/w);
    }
    else if(w > h) {
      xcs *= (w/h);
    }
    // Setup clip parameters
    // and initial clip position
    if (cmd.toLowerCase() == 'clip') {
      xcs *= -1;
      ycs *= -1;
      unclip = false;
      this.setClip(0, w, h, 0);
    }
    switch(edge.toLowerCase()) {
      case 'n':
        dt = -ycs; dr = 0;  db = 0;  dl = 0;
        if (unclip) this.setClip(h, w, h, 0);
        break;
      case 'ne':
        dt = -ycs; dr = xcs; db = 0;  dl = 0;
        if (unclip) this.setClip(h, 0, h, 0);
        break;
      case 'e':
        dt = 0;   dr = xcs; db = 0;  dl = 0;
        if (unclip) this.setClip(0, 0, h, 0);
        break;
      case 'se':
        dt = 0;   dr = xcs; db = ycs; dl = 0;
        if (unclip) this.setClip(0, 0, 0, 0);
        break;
      case 's':
        dt = 0;   dr = 0;  db = ycs; dl = 0;
        if (unclip) this.setClip(0, w, 0, 0);
        break;
      case 'sw':
        dt = 0;   dr = 0;  db = ycs; dl = -xcs;
        if (unclip) this.setClip(0, w, 0, w);
        break;
      case 'w':
        dt = 0;   dr = 0;  db = 0;  dl = -xcs;
        if (unclip) this.setClip(0, w, h, w);
        break;
      case 'nw':
        dt = -ycs; dr = 0;  db = 0;  dl = -xcs;
        if (unclip) this.setClip(h, w, h, w);
        break;
      case 'center':
        dt = -ycs;   dr = xcs;  db = ycs; dl = -xcs;
        if (unclip) this.setClip(h/2, w/2, h/2, w/2);
//        if (unclip) this.setClip(h, 0, 0, w);
        break;  
      default:
        alert("invalid direction in autoClip()");
    }
  }    // end if
  
  if (this.clipBy(dt, dr, db, dl))
    setTimeout(this.id+".autoClip("+null+","+null+","+dt+","+dr+","+db+","+dl+")",10);
  else
    this.clipping = false;
}


// Scroll the element by moving and clipping.

function cbeScrollBy(dx, dy) {

  var ct = this.getClipTop();
  var cr = this.getClipRight();
  var cb = this.getClipBottom();
  var cl = this.getClipLeft();

  // Don't scroll beyond the edge of the element
  if (cl + dx < 0) {
    cl = 0;
    dx = 0;
  }
  else if (cr + dx > this.getWidth()) {
    cr = cl + this.getClipWidth();
    dx = 0;
  }
  if (ct + dy < 0) {
    ct = 0;
    dy = 0;
  }
  else if (cb + dy > this.getHeight()) {
    cb = ct + this.getClipHeight();
    dy = 0;
  }

// Move and clip to simulate scrolling
  this.setClip(ct + dy, cr + dx, cb + dy, cl + dx);
  this.moveBy(-dx, -dy);
}


// Clip an element by a relative amount.
// Return false when there is no change.

function cbeClipBy(dt, dr, db, dl) {

  var ct = this.getClipTop();
  var cr = this.getClipRight();
  var cb = this.getClipBottom();
  var cl = this.getClipLeft();
  var w = this.getWidth();
  var h = this.getHeight();

  // Don't clip beyond the existing width and height of the element
  // and don't let top/bottom and left/right coords cross.

  // Top
  if (ct + dt < 0) {
    ct = 0; dt = 0;
  }
  else if (ct + dt > cb) {
    ct = cb; dt = 0;
  }
  // Right
  if (cr + dr < cl) {
    cr = cl; dr = 0;
  }
  else if (cr + dr > w) {
    cr = w; dr = 0;
  }
  // Bottom
  if (cb + db < ct) {
    cb = ct; db = 0;
  }
  else if (cb + db > h) {
    cb = h; db = 0;
  }
  // Left
  if (cl + dl < 0) {
    cl = 0; dl = 0;
  }
  else if (cl + dl > cr) {
    cl = cr; dl = 0;
  }

  this.setClip(ct + dt, cr + dr, cb + db, cl + dl);

  if (dt || dr || db || dl) return true;
  else return false;
}

// End of CrossBrowserElement Methods




// Get client area width.

function getClientWidth()
{
  var w = 0;
  if (is.nav4up) {
    w = window.innerWidth;
    if (document.height > window.innerHeight) // has vert scrollbar
      w -= 16;
  }
  else if (is.ie4up) {
    w = document.body.clientWidth;
  }
  else if (is.opera) {
    w = window.innerWidth;
  }
  return w;
}


// Get client area height.

function getClientHeight()
{
  var h = 0;
  if (is.nav4up) {
    h = window.innerHeight;
    if (document.width > window.innerWidth) // has horz scrollbar
      h -= 16;
  }
  else if (is.ie4up) {
    h = document.body.clientHeight;
  }
  else if (is.opera) {
    h = window.innerHeight;
  }
  return h;
}


// Get x scroll position.
// The number of pixels the document has scrolled horizontally.

function getScrollX()
{
  var offset;
  if (is.nav4up || is.opera) {
    offset = window.pageXOffset;
  }
  else if (is.ie4up) {
    offset = document.body.scrollLeft;
  }
  return offset;
}

// Get y scroll position.
// The number of pixels the document has scrolled vertically.

function getScrollY()
{
  var offset;
  if (is.nav4up || is.opera) {
    offset = window.pageYOffset;
  }
  else if (is.ie4up) {
    offset = document.body.scrollTop;
  }
  return offset;
}

// Get a reference to an Element object
// This is a cross-browser version of getElementById().

function getElementRef(eleId)
{
  var ele;

  if (document.getElementById)
    ele = document.getElementById(eleId);
  else if (is.ie4up)
    ele = document.all[eleId];
  else if (is.nav4up)
    ele = document.layers[eleId];

  return ele;
}


// ClientSnifferJr Object Constructor.
// This is a simplified version of the Client Sniffer code found at
// http://developer.netscape.com/docs/examples/javascript/browser_type.html

function ClientSnifferJr()
{
  
  this.mac = (navigator.platform != "Win32");

  this.ua = navigator.userAgent.toLowerCase();
  this.major = parseInt(navigator.appVersion);
  this.minor = parseFloat(navigator.appVersion);
  this.nav   = (
    (this.ua.indexOf('mozilla')!=-1)
    && ((this.ua.indexOf('spoofer')==-1)
    && (this.ua.indexOf('compatible') == -1))
  );
  this.nav4  = (this.nav && (this.major == 4));
  this.nav4up= (this.nav && (this.major >= 4));
  this.nav5up= (this.nav && (this.major >= 5));
  this.gecko = (this.ua.indexOf('gecko') != -1); 
  this.ie    = (this.ua.indexOf("msie") != -1);
  this.ie3   = (this.ie && (this.major == 2));
  this.ie4   = (
    this.ie && (this.major == 4)
    && (this.ua.indexOf("msie 5.0")==-1)
  );
  this.ie4up = (this.ie  && (this.major >= 4));
  this.ie5up = (this.ie && !this.ie3 && !this.ie4);
  this.opera = (this.ua.indexOf("opera") != -1);
  this.hotjava = (this.ua.indexOf("hotjava") != -1); 
  this.webtv = (this.ua.indexOf("webtv") != -1);
  this.aol   = (this.ua.indexOf("aol") != -1); 
}

var is = new ClientSnifferJr();

function dd_onload() // can be run before the browser declares onload!
{ 
	if (dd_loaded) return; // duplicates can happen
	if ((!uid) || (!map)) alert('Game engine error: encryption keys not found.');
	dd_loaded = true;
	document.chatform.mychat.value='Type here and press ENTER';
	document.chatform.mychat.focus();
	dd_init();
	
	// BIG YUKKY DEBUG
	if (dd_v2_debug)
	{
	ddgx=10; ddgy=10;
	ddpx=grid_to_pixelX(ddgx,ddgy);
	ddpy=grid_to_pixelY(ddgx,ddgy);
	ddggx = pixel_to_gridX(ddpx,ddpy);
	ddggy = pixel_to_gridY(ddpx,ddpy);
	alert('DEBUG GRID TEST: ddgx='+ddgx+' ddgy='+ddgy+' ddpx='+ddpx+' ddpy='+ddpy+' ddggx='+ddggx+' ddggy='+ddggy);
	}
	
	
} 





















////////////////////////////////////////////////////////////////
// Digital Deadwood Online Game Engine - (c) 2004
////////////////////////////////////////////////////////////////
// For use only by TDG Communications on www.digitaldeadwood.com
////////////////////////////////////////////////////////////////
// Programmed by Christer Kaitila in PHP and Javascript
// Freelance programmer for hire: www.orangeview.net
////////////////////////////////////////////////////////////////
// Additional code credits - many thanks for online tutorials!
////////////////////////////////////////////////////////////////
// http://www.brainjar.com
// http://lineoflight.com/
// http://www.mikefoster.f2s.com/
// http://www.yasd.com/dynatech/xobjsintro.htm
// http://members.aol.com/mhall75819
// http://www.mts.net/~tfriesen/
// http://dannyg.com/
// http://www.w3.org/









































































































































































































































































































































































































































































































