/*
VERSION:		2.8
2.8:			Added lookAtCoords() & lookAtSprite().  Altered lookAt() to use lookAtCoords().
2.7:			Set both init frame and internal frame when charset & frames are changed.
2.5:			Uses setTimeout() when internal charset loads so the mask can be set properly.
2.3:			Added getParam() to retrieve individual settings
2.1:			When "frames" is changed, "frame" is adjusted as needed
2.0:			When "directions" is changed, "direction" is adjusted as needed
1.9:			Added isFacing() funciton.		Corrected directional string translation  (use floor()  instead of round()
1.8:			Initial settings are copied into a new object rather than modifying the passed object
1.7:			Altered init frame when setting max frames lower
1.6:			Explained the default settings at the beginning
1.5:			Removed  updateAfterEvent()  to avoid performance issues with multiple on-screen sprites
1.4:			Made getParams() return a copy of the init data, instead of a reference
1.3:			Moved updatAfterEvent() into update(), to prevent flicker when loading external files
1.2:			Made the movieClipLoader persistant outside of set_charset, to allow it to be used for external events
1.1:			Fixed a glitch where "yoyo" animation made 1-frame sprites blink endlessly
1.0:			Completely revised settings functions, making it possible to easily change multiple settings at once.
					Completely rewrote sprite code to clean things up.
	
NOTE:
	This is sprite system 2.
	It is not compatible with the old sprite system that used  makeSprite()
	This system has been completely revised to allow settings to be sent and recieved en-masse, via objects.
	
DESCRIPTION:
	Pros:		Multiple settings can be sent to the system at once, without worrying about which order they go in.
				A single image can be used,  and can contain many poses.
				You can specify the:  size,  number of poses,  number animation frames,  number of directions.
				Animation speed can be controlled.
				Animation can occelate back & forth,	play once,  or loop.
				Any number of settings can be altered via a single function.
	Cons:		?
	
NOTE:
	This sprite system places the character's feet at the origin point.	(Feet:  1/2 image width, full image height)
	
	
USAGE:
	#include "functions/sprite.as"
	newSprite();			// minimum usage		(nothing is seen, but it can be modified later)
	
	
	#include "functions/sprite.as"
	var settings = {
		charset				:	"charset/marle.png",
		direction			:	2,				//(base zero)
		directions		:	4,				//(base one)		(amount of directions)
		frame					:	1,				//(base zero)
		frames				:	3,				//(base one)		(amount of frames)
		pose					:	0,				//(base zero)
		columns				:	4,				//(base zero)
		rows					:	2,				//(base zero)
		animType			:	"yoyo",
		animDirection	:	1,
		delay					:	3,				//(base one)
		isAnimating		:	true
	}
	mySprite = newSprite( settings, [parent], [instanceName], [depth] );			// maximum usage		(rm2k settings)
	
	
	mySprite.setParams({isAnimating:true});
	
	
	spriteState = mySprite.getParams();
	
	
DEFAULT SETTINGS:
	You can skip most settings when you setup a sprite.
	When you do, it defaults to these values:
		charset				:	REQUIRED
		direction			:	0
		directions		:	1
		frame					:	0
		frames				:	1
		pose					:	0
		columns				:	1
		rows					:	1
		animType			:	"loop"
		animDirection	:	1
		delay					:	4
		isAnimating		:	true
	
DEPENDANCIES:
	nextDepth.as

DEPTHS:
	0		previous_mc
	1		mask_mc
	2		image_mc
*/



function newSprite( newSettings, newTarget, newName, newDepth )
{
	// resolve movieClip parameters
	// target
	var newTarget = (newTarget) ? newTarget : this;
	// name
	var newName = (newName) ? newName : "sprite_"+Math.floor(Math.random()*9999);
	while(newTarget[newName]){
		var newName = "sprite_"+Math.floor(Math.random()*9999);
	}// while:  this movieClip already exists
	// depth
	#include "nextDepth.as"
	var newDepth = (newDepth!=undefined) ? newDepth : nextDepth(newTarget);
	
	
	// create movieClip
	var _this = newTarget.createEmptyMovieClip( newName, newDepth );
	
	
	// resolve optional parameters  &  copy settings
	var initSettings = {};
	// charset
	initSettings.charset = newSettings.charset;
	// direction
	initSettings.direction = (newSettings.direction!=undefined) ? newSettings.direction : 0;
	// directions
	initSettings.directions = (newSettings.directions!=undefined) ? newSettings.directions : 1;
	// frame
	initSettings.frame = (newSettings.frame!=undefined) ? newSettings.frame : 0;
	// frames
	initSettings.frames = (newSettings.frames!=undefined) ? newSettings.frames : 1;
	// pose
	initSettings.pose = (newSettings.pose!=undefined) ? newSettings.pose : 0;
	// columns
	initSettings.columns = (newSettings.columns!=undefined) ? newSettings.columns : 1;
	// rows
	initSettings.rows = (newSettings.rows!=undefined) ? newSettings.rows : 1;
	// animType
	initSettings.animType = (newSettings.animType!=undefined) ? newSettings.animType : "loop";
	// animDirection
	initSettings.animDirection = (newSettings.animDirection!=undefined) ? newSettings.animDirection : 1;
	// delay
	initSettings.delay = (newSettings.delay!=undefined) ? newSettings.delay : 4;
	// isAnimating
	initSettings.isAnimating = (newSettings.isAnimating!=undefined) ? newSettings.isAnimating : true;
	// charset MUST be defined
	
	
	// init settings
	_this.init = {};
	
	// internal settings
	_this.internal = {};
	
	
	// spriteWidth & spriteHeight are initialized here, but will be derived upon loading
	_this.spriteWidth = 0;
	_this.spriteHeight = 0;
	
	
	// create mask
	_this.mask_mc = _this.createEmptyMovieClip( "mask_mc", 1 );
	_this.mask_mc.beginFill(0xff0000, 0);
	_this.mask_mc.lineTo(16,0);
	_this.mask_mc.lineTo(16,16);
	_this.mask_mc.lineTo(0,16);
	_this.mask_mc.lineTo(0,0);
	_this.mask_mc.endFill();
	
	
	
	// initialize offsets
	_this.offsetX = 0;
	_this.offsetY = 0;
	
	
	// update flag
	_this.refresh = false;
	
	
	// chipset loader		(also fires events)
	_this.loader = new MovieClipLoader();
	
	
	// ___________________________________________________________
	// FUNCTIONS
	
	// update()		(using "internal" settings)
	// position image_mc
	_this.update = function()
	{
		// position image_mc
		// horz
		var column = _this.internal.pose%_this.internal.columns;
		_this.image_mc._x = _this.offsetX  -  column*_this.spriteWidth*_this.internal.frames  -  _this.internal.frame*_this.spriteWidth;
//		trace("_x: "+_this.image_mc._x+"   offsetX: "+_this.offsetX+"   column: "+column+"   spriteWidth: "+_this.spriteWidth+"   frames: "+_this.internal.frames+"   frame: "+_this.internal.frame);
		// vert
		var row = Math.floor(_this.internal.pose/_this.internal.columns);
		_this.image_mc._y = _this.offsetY  -  row*_this.spriteHeight*_this.internal.directions  -  _this.internal.direction*_this.spriteHeight;
//		trace("_y: "+_this.image_mc._y+"   offsetY: "+_this.offsetY+"   row: "+row+"   spriteHeight: "+_this.spriteHeight+"   directions: "+_this.internal.directions+"   direction: "+_this.internal.direction);
		// --------------------
		//updateAfterEvent();
		_this.refresh = false;
	}// update()
	
	
	
	
	
	// update mask's size & offset
	_this.updateMask = function()
	{
		// resize
		_this.mask_mc._width = _this.spriteWidth;
		_this.mask_mc._height = _this.spriteHeight;
		// reposition
		_this.mask_mc._x = _this.offsetX;
		_this.mask_mc._y = _this.offsetY;
	}// updateMask()
	
	
	
	
	
	// update image size & offset  And  update mask's size & offset
	_this.updateSize = function()
	{// requires:		image_mc,  mask_mc,  internal.columns,  internal.rows,  internal.frames,  internal.directions
		// update spriteWidth & spriteHeight
		_this.spriteWidth = _this.image_mc._width / _this.internal.columns / _this.internal.frames;
		_this.spriteHeight = _this.image_mc._height / _this.internal.rows / _this.internal.directions;
		// update image offset
		_this.offsetX = -_this.spriteWidth / 2;
		_this.offsetY = -_this.spriteHeight;
		// update mask
		_this.updateMask();
	}// updateSize()
	
	
	
	
	
	// charset
	_this.set_charset = function( new_charset, newThis )
	{
		var _this = newThis || _this;
		// take a snapshot to retain an image during loading to prevent flickering
		_this.removeSnapshot = function(){
			_this.previous_mc.removeMovieClip();		// remove previous snapshot
		}
		delete _this.previous_pic;		// remove previous snapshot image
		_this.previous_pic = new flash.display.BitmapData( _this.mask_mc._width, _this.mask_mc._height, true, 0x00000000 );
		var copyPosition = new flash.geom.Matrix();
		copyPosition.translate(-_this.offsetX, -_this.offsetY);		// reposition the copy area relative to the origin
		_this.previous_pic.draw( _this, copyPosition );
		_this.previous_mc.removeMovieClip();		// remove previous snapshot
		_this.createEmptyMovieClip( "previous_mc", 0 );
		_this.previous_mc.attachBitmap( _this.previous_pic, 0 );
		_this.previous_mc._x = _this.offsetX;
		_this.previous_mc._y = _this.offsetY;
	
		
		
		// movieclip linkage
			// create:		_this.image_mc		_this.image_pic
			// loader:		_this.loader
			// pre ops:		image_mc._alpha=0		_this.loader;
			// post ops:	update()		_this.frame		removeLastPic()		_this.onLoad()		image_mc._alpha=100		setMask()		delete _this.loader;
		
		// pre-ops
		_this.loader.new_charset = new_charset;
		_this.loader._this = _this;
		
		
		// set frame
		_this.internal.frame = _this.init.frame;
		
		
		// post-ops
		_this.loader.onLoadInit = function( image_mc )
		{// if:  image loaded
			var _this = image_mc._parent;
			// update image size & offset  And  update mask's size & offset
			_this.updateSize();
			// apply the mask
			_this.image_mc.setMask( _this.mask_mc );
			// remove temporary image
			_this.previous_mc.removeMovieClip();		// remove placeholder image
			// immediately update the display
			_this.update();
			// alpha = 100
			_this.image_mc._alpha = 100;
			// announce load
			_this.onLoad();					// announce load finished
		}// if:  image loaded
		_this.loader.onLoadError = function()
		{// if:  external file not found
			/*
			// restore previous charset
			trace("_this.init.charset: "+_this.init.charset+"   _this.init.charset.length: "+_this.init.charset.length);
			if(_this.init.charset.length>0){
				_this.set_charset( _this.init.charset );
			}else{
				// continue with invisible charset
				_this.onLoad();					// announce load finished
			}
			*/
		}// if:  external file not found
		
		
		// main
		// // attempt movieClip linkage
		_this.loader.externalFile = false;
		_this.image_mc.removeMovieClip();
		_this.createEmptyMovieClip("image_mc", 2);
		_this.image_mc._alpha = 0;															// alpha = 0
		_this.image_mc.attachMovie( new_charset, "image", 2);
		if(	_this.image_mc._width == undefined  ||	_this.image_mc._width == 0)
		{// if:  no movieClip loaded
			// attempt bitmap linkage
			_this.image_pic.dispose();
			_this.image_pic = flash.display.BitmapData.loadBitmap( new_charset );
			_this.image_mc.attachBitmap(_this.image_pic, 0);
			if(	_this.image_mc._width == undefined  ||	_this.image_mc._width == 0)
			{// if:  no bitmap loaded
				// attempt external file
				_this.loader.externalFile = true;
				_this.loader.loadClip( new_charset, _this.image_mc );
			}// if:  no bitmap loaded
			else
			{// if:  bitmap attach succeeded
				setTimeout( _this.loader.onLoadInit, 1, _this.image_mc );
				//_this.loader.onLoadInit( _this.image_mc );
			}// if:  bitmap attach succeeded
		}// if:  no movieClip loaded
		else
		{// if:  movieClip attach succeeded
			setTimeout( _this.loader.onLoadInit, 1, _this.image_mc );
			//_this.loader.onLoadInit( _this.image_mc );
		}// if:  movieClip attach succeeded
		
		
		// --------------
		_this.internal.charset = new_charset;
	}// set_charset()
	
	
	
	
	// directions
	_this.set_directions = function( new_directions )
	{
		// enforce minimum
		if(new_directions<0)
			var new_directions=1;
		// --------------
		_this.internal.directions = Math.floor(Math.abs(Number(new_directions)));		// only positive integers
		_this.internal.direction %= _this.internal.directions;
		// --------------
		// immediately recalculate spriteWidth & spriteHeight  And  update the mask
		_this.updateSize();
		// update the display this frame
		_this.refresh = true;
	}// set_directions()
	
	
	
	
	// direction
	_this.set_direction = function( new_direction )
	{
		// interpret clockwise english values  (works for RPGs, Platformers, Escape Velocity, etc...)
		var incr = _this.internal.directions/4;
		if(new_direction=="up"){
			var new_direction = 0;
		}else if(new_direction=="right"){
			var new_direction = Math.floor(1*incr);
		}else if(new_direction=="down"){
			var new_direction = Math.floor(2*incr);
		}else if(new_direction=="left"){
			var new_direction = Math.floor(3*incr);
		}
		// limit minimum to looping range
		while(new_direction < 0)
			new_direction += _this.internal.directions;
		// loop the maximum
		new_direction %= _this.internal.directions;
		// update the display this frame
		_this.refresh = true;
		// --------------
		_this.internal.direction = Math.floor(Number(new_direction));		// as an integer
	}// set_direction()
	
	
	
	
	// frames
	_this.set_frames = function( new_frames )
	{
		if(_this.internal.frame > new_frames-1)
			_this.internal.frame = new_frames-1;
		if(_this.init.frame > new_frames-1)
			_this.init.frame = new_frames-1;
		// --------------
		_this.internal.frames = Math.floor(Math.abs(Number(new_frames)));		// only positive integers
		if(_this.internal.frame > _this.internal.frames-1)
			_this.internal.frame = _this.internal.frames-1;
		// --------------
		_this.init.frame = _this.internal.frame;
		// immediately recalculate spriteWidth & spriteHeight  And  update the mask
		_this.updateSize();
		// update the display this frame
		_this.refresh = true;
	}// set_frames()
	
	
	
	
	// frame
	_this.set_frame = function( new_frame )
	{
		// enforce minimum
		if(new_frame < 0)
			var new_frame = 0;
		// enforce maximum
		if(new_frame > _this.internal.frames-1)
			var new_frame = _this.internal.frames-1;
		// update the display this frame
		_this.refresh = true;
		// --------------
		_this.init.frame = _this.internal.frame = Math.floor(Math.abs(Number(new_frame)));		// only positive integers
	}// set_frame()
	
	
	
	
	// columns
	_this.set_columns = function( new_columns )
	{
		_this.internal.columns = Math.floor(Math.abs(Number(new_columns)));		// only positive integers
		// --------------
		// immediately recalculate spriteWidth & spriteHeight  And  update the mask
		_this.updateSize();
		// update the display this frame
		_this.refresh = true;
	}// set_columns()
	
	
	
	
	// rows
	_this.set_rows = function( new_rows )
	{
		_this.internal.rows = Math.floor(Math.abs(Number(new_rows)));		// only positive integers
		// --------------
		// immediately recalculate spriteWidth & spriteHeight  And  update the mask
		_this.updateSize();
		// update the display this frame
		_this.refresh = true;
	}// set_rows()
	
	
	
	
	// pose
	_this.set_pose = function( new_pose )
	{
		var maxPose = (_this.internal.columns*_this.internal.rows)-1;
		// enforce minimum
		if(new_pose<0)
			var new_pose=0;
		// enforce maximum
		if(new_pose>maxPose)
			var new_pose=maxPose;
		// update the display this frame
		_this.refresh = true;
		// --------------
		_this.internal.pose = Math.floor(Math.abs(Number(new_pose)));		// only positive integers
	}// set_pose()
	
	
	
	
	// animType
	_this.set_animType = function( new_animType )
	{
		// only allow valid values
		if(new_animType == "loop"
		|| new_animType == "yoyo"
		|| new_animType == "once")
			_this.internal.animType = String(new_animType);
	}// set_animType()
	
	
	
	
	// animDirection
	_this.set_animDirection = function( new_animDirection )
	{
		// enforce minimum
		if(new_animDirection<-1)
			var new_animDirection=-1;
		// enforce maximum
		if(new_animDirection>1)
			var new_animDirection=1;
		// only allow valid values
		if(new_animDirection == -1
		|| new_animDirection == 1)
			_this.internal.animDirection = Number(new_animDirection);
	}// set_animDirection()
	
	
	
	
	// delay
	_this.set_delay = function( new_delay )
	{
		// enforce minimum		(can be decimal, cannot be Zero)
		if(new_delay<=0)
			var new_delay=1;
		// --------------
		_this.internal.delay = Number(new_delay);
	}// set_delay()
	
	
	
	
	// isAnimating
	_this.set_isAnimating = function( new_isAnimating )
	{
		// catch string versions of "true" and "false"
		if(new_isAnimating.toLowerCase() == "true")
			var new_isAnimating = true;
		if(new_isAnimating.toLowerCase() == "false")
			var new_isAnimating = false;
		if(new_isAnimating != _this.internal.isAnimating)
		{// if:  changed
			if(new_isAnimating){
				// -> ON
				_this.advanceAnimation();
			}else{
				// -> OFF
				_this.internal.frame = Number(_this.init.frame);
			}
			// update the display this frame
			_this.refresh = true;
		}// if:  changed
		// --------------
		_this.internal.isAnimating = Boolean(new_isAnimating);
	}// set_isAnimating()
	
	
	
	
	
	// setParams()
	_this.setParams = function( newSettings )
	{
		// charset		(image_mc, mask_mc size, offsetX, offsetY, spriteWidth, spriteHeight)		(asynchronous)
		if( newSettings.charset != undefined
		&&	newSettings.charset != _this.internal.charset){
			_this.set_charset( newSettings.charset );
			//setTimeout( _this.set_charset, 1, newSettings.charset, _this );
			_this.init.charset = _this.internal.charset;
		}
		// directions
		if( newSettings.directions != undefined
		&&	newSettings.directions != _this.internal.directions){
			_this.set_directions( newSettings.directions );
			_this.init.directions = _this.internal.directions;
		}
		// direction
		if( newSettings.direction != undefined
		&&	newSettings.direction != _this.internal.direction){
			_this.set_direction( newSettings.direction );
			_this.init.direction = _this.internal.direction;
		}
		// frames
		if( newSettings.frames != undefined
		&&	newSettings.frames != _this.internal.frames){
			_this.set_frames( newSettings.frames );
			_this.init.frames = _this.internal.frames;
		}
		// frame
		if( newSettings.frame != undefined
		&&	newSettings.frame != _this.internal.frame){
			_this.set_frame( newSettings.frame );
			_this.init.frame = _this.internal.frame;
		}
		// columns
		if( newSettings.columns != undefined
		&&	newSettings.columns != _this.internal.columns){
			_this.set_columns( newSettings.columns );
			_this.init.columns = _this.internal.columns;
		}
		// rows
		if( newSettings.rows != undefined
		&&	newSettings.rows != _this.internal.rows){
			_this.set_rows( newSettings.rows );
			_this.init.rows = _this.internal.rows;
		}
		// pose
		if( newSettings.pose != undefined
		&&	newSettings.pose != _this.internal.pose){
			_this.set_pose( newSettings.pose );
			_this.init.pose = _this.internal.pose;
		}
		// animType
		if( newSettings.animType != undefined
		&&	newSettings.animType != _this.internal.animType){
			_this.set_animType( newSettings.animType );
			_this.init.animType = _this.internal.animType;
		}
		// animDirection
		if( newSettings.animDirection != undefined
		&&	newSettings.animDirection != _this.internal.animDirection){
			_this.set_animDirection( newSettings.animDirection );
			_this.init.animDirection = _this.internal.animDirection;
		}
		// delay
		if( newSettings.delay != undefined
		&&	newSettings.delay != _this.internal.delay){
			_this.set_delay( newSettings.delay );
			_this.init.delay = _this.internal.delay;
		}
		// isAnimating
		if( newSettings.isAnimating != undefined
		&&	newSettings.isAnimating != _this.internal.isAnimating){
			_this.set_isAnimating( newSettings.isAnimating );
			_this.init.isAnimating = _this.internal.isAnimating;
		}
		
		
		if(_this.refresh){
			_this.update();		// update display position
		}
	}// setParams()
	
	
	
	// getParams()
	_this.getParams = function()
	{
		// make a copy of the initial settings
		var output = {};
		for(var nam in _this.init)
			output[nam] = _this.init[nam];
		// return the copy
		return output;
	}// getParams()
	
	
	
	_this.getParam = function( varName )
	{
		return _this.internal[varName];
	}// getParam()
	
	
	
	
	
	// ___________________________________________________________
	// LOOP
	
	// advanceAnimation()
	_this.advanceAnimation = function()
	{
		_this.internal.frame += _this.internal.animDirection;
		switch(_this.internal.animType)
		{
			case "loop":
				// loop from minimum
				if(_this.internal.frame<0){
					_this.internal.frame += _this.internal.frames;
				}
				// loop from maximum
				else if(_this.internal.frame>=_this.internal.frames){
					_this.internal.frame -= _this.internal.frames;
				}
			break;
			case "once":
				// limit to minimum
				if(_this.internal.frame<0){
					_this.internal.frame = 0;
				}
				// limit to maximum
				else if(_this.internal.frame>=_this.internal.frames){
					_this.internal.frame = _this.internal.frames-1;
				}
			break;
			case "yoyo":
				// reverse beyond minimum
				if(_this.internal.frame<0){
					_this.internal.frame += 2;						// undo last anim  &  advance in the opposite direction
					_this.internal.animDirection *= -1;		// reverse animation direction
				}
				// reverse beyond maximum
				else if(_this.internal.frame>=_this.internal.frames){
					_this.internal.frame -= 2;						// undo last anim  &  advance in the opposite direction
					_this.internal.animDirection *= -1;		// reverse animation direction
				}
				
				// enforce max frame limit		(for sprites with only 1 frame of animation)
				if(_this.internal.frame < 0)
					_this.internal.frame = 0;
				if(_this.internal.frame >= _this.internal.frames)
					_this.internal.frame = _this.internal.frames-1;
			break;
		}// switch:  animType
	}// advanceAnimation()
	
	
	
	// loop()
	_this.fps = 30;
	_this.loop = function()
	{
		if(_this.internal.isAnimating)
		{// if:  animation is on
			_this.advanceAnimation();
		}// if:  animation is on
		_this.update();
		_this.loopInterval = setTimeout( _this.loop, 1000/_this.fps*_this.internal.delay );
	}// loop()
	_this.loopInterval = setTimeout( _this.loop, 0 );
	
	
	
	
	
	// ___________________________________________________________
	// EXTRA FEATURES
	
	_this.lookAtCoords = function()
	{
		var destX = arguments[0];
		var destY = arguments[1];
		// get a unit vector
		var xDiff = destX - _this._parent._x;
		var yDiff = destY - _this._parent._y;
		var dist = Math.sqrt( xDiff*xDiff + yDiff*yDiff );
		var xUnit = xDiff / dist;
		var yUnit = yDiff / dist;
		
		// compare x & y
		if( Math.abs(yUnit) > Math.abs(xUnit) )
		{
			// vert
			if( yUnit < 0)
			{
				// up
				_this.setParams( {direction:"up"} );
			}else{
				// down
				_this.setParams( {direction:"down"} );
			}// if:  up or down
		}else{
			// horz
			if( xUnit < 0 )
			{
				// left
				_this.setParams( {direction:"left"} );
			}else{
				// right
				_this.setParams( {direction:"right"} );
			}// if:  left or right
		}// if:  vert or horz
	}// lookAtCoords()
	
	
	
	_this.lookAtSprite = function( sprite2 ){
		_this.lookAtCoords( sprite2._x, sprite2._y );
	}// lookAtSprite()
	
	
	
	// This makes the specified sprite look at another sprite.
	_this.lookAt = function( sprite1, sprite2 )
	{
		// get a unit vector
		var xDiff = sprite2._x - sprite1._x;
		var yDiff = sprite2._y - sprite1._y;
		var dist = Math.sqrt( xDiff*xDiff + yDiff*yDiff );
		var xUnit = xDiff / dist;
		var yUnit = yDiff / dist;
		
		// compare x & y
		if( Math.abs(yUnit) > Math.abs(xUnit) )
		{
			// vert
			if( yUnit < 0)
			{
				// up
				_this.setParams( {direction:"up"} );
			}else{
				// down
				_this.setParams( {direction:"down"} );
			}// if:  up or down
		}else{
			// horz
			if( xUnit < 0 )
			{
				// left
				_this.setParams( {direction:"left"} );
			}else{
				// right
				_this.setParams( {direction:"right"} );
			}// if:  left or right
		}// if:  vert or horz
	}// lookAt()
	
	
	
	_this.isFacing = function( checkDir )
	{
		var incr = _this.internal.directions/4;
		if(checkDir=="up"){
			var checkDir = 0;
		}else if(checkDir=="right"){
			var checkDir = Math.floor(1*incr);
		}else if(checkDir=="down"){
			var checkDir = Math.floor(2*incr);
		}else if(checkDir=="left"){
			var checkDir = Math.floor(3*incr);
		}
		// limit minimum to looping range
		while(checkDir < 0)
			checkDir += _this.internal.directions;
		// loop the maximum
		checkDir %= _this.internal.directions;
		return (_this.internal.direction == checkDir);
	}// isFacing()
	
	
	
	
	
	// ___________________________________________________________
	// SETUP
	
	// apply initial settings
	_this.setParams( initSettings );
	
	
	
	
	
	// ___________________________________________________________
	// CLEAN-UP
	_this.onUnload = function()
	{
		clearTimeout( _this.loopInterval );
	}// onUnload()
	
	
	
	
	
	// ___________________________________________________________
	// return a reference
	return _this;
}// newSprite()