bool WarnCollision(NavMeshAgentWrapper navigator, RaycastHit hit){

		// someone is coming	
//Debug.Log (name+" got warning from "+navigator.name);
		if (!isNavigating &&
			!holdPosition &&
			!lockPosition &&
			GetComponent<TaskCharacter>().executingScript == null){// && priority > navigator.priority){ //if we are less important than the mover
			// don't let a character move out of the way if they are still animating
			// moved this inside so we only test if the other checks said it was okay.
			if ( GetComponent<AnimationManager>().CanWalk() == false ) //this only tests CharacterAnimState==Idle
			{
				UnityEngine.Debug.LogError ("NavMeshAgentWrapper.WarnCollision(" + this.name + ") : can't move out of the way, still animating!");
				return false;
			}

			// what if we just move forward or back one radius ?
			Vector3 dir = hit.point - transform.position;
			dir.y=0;
			moveStartTime = Time.time;
			avoidCount = 0;
			FreeMe();
			destPos = transform.position - dir.normalized*m_navMeshAgent.radius*1.5f;
			finalDestination = destPos;
			hasFinalRotation = false;
			// can we give a final rotation facing the patient ?

			hasFinalRotation = true;
			Vector3 rotationVector = GameObject.Find("lookPatient").transform.position-destPos;
			rotationVector.y = 0;
			finalRotation = Quaternion.LookRotation(rotationVector);

			GetComponent<AnimationManager>().Walk(0.25f);
			GetComponent<TaskCharacter>().IsInPosition(""); // clears atNode so we have to nav back
			m_navMeshAgent.SetDestination(destPos);
			makingWayFor = navigator;
#if DEBUG_NAVIGATION
			Debug.Log (name+" Moving to avoid "+navigator.name+" hold="+holdPosition);
#endif
			// blending forward/back with hit direction.
//			if (Vector3.Dot(dir,transform.forward) > 0)
//				m_navMeshAgent.SetDestination(transform.position - transform.forward*m_navMeshAgent.radius);
//			else
//				m_navMeshAgent.SetDestination(transform.position + transform.forward*m_navMeshAgent.radius);
			
			navRequested = true;
			isNavigating = false;
			return true;
		}
		else{
			if (makingWayFor == navigator) 
				return true; // i am already stepping out of your way.
			else{
//Debug.Log (name+" won't move to make way for "+navigator.name);
				return false; // cant help you, i am busy.
			}
		}
	}
	void Update ()
	{
		avoidTime -= Time.deltaTime;
		if (navRequested)
		{
			if (m_navMeshAgent == null){
				Debug.LogWarning (name+" lost agent while navRequested.");
				m_navMeshAgent = RecreateAgent();
				lastAvoidCheckTime = 0; // cause us to take the timeout exit path to our destination
			}
			
			if (m_navMeshAgent.hasPath)
			{
				navRequested = false;
				isNavigating = true;
//				if (!CheckForAvoidance()) // this will check every frame while needed
						lastAvoidCheckTime = Time.time;
			} else if (Time.time - lastAvoidCheckTime > avoidCheckInterval) {
				// failed to path in time, return failure
//Debug.LogWarning(name+" NavMeshAgent failed to find initial path fast enough. Warping!");
				SendMessageUpwards("OnNavigationRequestFailed",SendMessageOptions.DontRequireReceiver);
				navRequested = false;
				m_navMeshAgent.Stop();
//				GetComponent<AnimationManager>().StopWalk(0.5f);
				m_navMeshAgent.updateRotation = false; // apparently this is needed to keep the positino and ritation from being updated
				
				// new code here: 4/2/13 PAA
				// this works well, but we have to be careful that the destination is a good one.
				// people were sinking down to avoid positions...
				// it didn't solve the very short distance navigation problem, though.
				isNavigating = true;
				failsafeSlider = 1.0f; // lerp to the failed point...
				moveStartTime = Time.time-moveTimeout-1.0f; // ensure that the lerp starts now.
				// somehow, final destination can end up below the floor, so we are correcting for that here.
//				finalDestination.y = transform.position.y; // don't lerp vertically
				
			}
		}
		
		if (isNavigating)
		{
			if (failsafeSlider <= 0 && Time.time - moveStartTime > moveTimeout)
				failsafeSlider = 1.0f;
			
			if (failsafeSlider > 0){ // we have run into trouble so just lerp to the final destination
//				Debug.LogWarning(name+" navigation failed to complete, Warping!");
				isAvoiding = false;
				// we should turn off the collider at this point to avoid pushing anybody aside!
				if (collider != null)
					collider.isTrigger = true; // this didn't work, check on the nav mesh agent and capsule collider
				
				if (m_navMeshAgent != null){
					//m_navMeshAgent.SetDestination(finalDestination); // let the final lerp do the node alignment
					// There is an unfortunate characteristic of the Unity NavMeshAgent, that when you take over
					// moving the object like this, the agent retains it's last position, and the next time
					// you let the agent drive, it snaps back to that spot.  
					// The only way I found to get around this is to Destroy then Recreate the agent!
					m_navMeshAgent.Stop(true);
					m_navMeshAgent.ResetPath();
					Object.Destroy(m_navMeshAgent);
					m_navMeshAgent = null;
				}
//				m_navMeshAgent.Stop(true); // let the final lerp do the node alignment
//				m_navMeshAgent.updateRotation = false; 
//				m_navMeshAgent.updatePosition = false;
				transform.position = Vector3.Lerp(transform.position,finalDestination,1.0f-failsafeSlider);
				failsafeSlider -= Time.deltaTime/2.0f; // this gives us a 2 second lerp.
				if (failsafeSlider < 0.5f) GetComponent<AnimationManager>().StopWalk(0.25f); // start blending out the walk...
				if (failsafeSlider <= 0 && Time.time - moveStartTime > moveTimeout){
					transform.position = finalDestination;
					if (m_navMeshAgent == null) RecreateAgent ();
					isNavigating = false;
					failsafeSlider = 0;
					if (collider != null)
						collider.isTrigger = false;
					LockMe ();
					makingWayFor = null; // if i was getting out of someone's way, i have done that now.
					SendMessageUpwards("OnNavigationRequestSucceeded",SendMessageOptions.DontRequireReceiver); // should really wait for alignment to complete for this
					GetComponent<TaskCharacter>().Arrive();
					GetComponent<AnimationManager>().StopWalk(0.25f); // this would be better moved to TaskCharacter.Arrive()
				}
				return;
			}
			
			distance = m_navMeshAgent.remainingDistance;
			if (!isAvoiding){ // blend to normal speed if not avoiding
/*				
				if (m_navMeshAgent.speed < defaultSpeed)
					m_navMeshAgent.speed = m_navMeshAgent.speed*1.1f;
				else
					m_navMeshAgent.speed = defaultSpeed;
*/
				
				// lets start the alignment a bit earlier
				if ( hasFinalRotation && distance < 3.0f*m_navMeshAgent.radius){ 
					m_navMeshAgent.updateRotation = false;
						
					// if we were walking backwards, transfer the heading rotation up to the parent and let the lerp to
					// final rotation do the final alignment
					if (heading != 0 && headingTransform != null){
						// fool the nav mesh agent into walking backwards by setting a rotation and counter rotation
						// on the two top hierarchy nodes
						foreach (GameObject go in reattachedObjects){
							go.transform.parent = null;	
						}								
						transform.rotation *= Quaternion.AngleAxis(-heading,Vector3.up);
						headingTransform.localRotation = Quaternion.identity;
						heading = 0;
						foreach (GameObject go in reattachedObjects){
							go.transform.parent = transform;	
						}
						reattachedObjects.Clear();
					}
					if (lerpFromRotation == Quaternion.identity)
						lerpFromRotation = transform.rotation;
					
					float denominator = 3.0f*m_navMeshAgent.radius;
					float numerator = denominator - distance;
					
					
					float lrp = 0.75f*numerator/denominator;// (3.0f*m_navMeshAgent.radius - distance) / 3.0f*m_navMeshAgent.radius;
					// technically, this kind of lerp should retain the starting value instead of
					// using the current value, as this leads to a non-linear interpolation, but this is easier to code
					Quaternion desiredRotation = Quaternion.Lerp(lerpFromRotation,finalRotation,lrp);
					// if the angle is too great, limit rotation and hold 'distance' above threshold until rotation can complete to avoid snapping on short trips
					float remainingAngle;
					Vector3 rotAxis;
					Quaternion delta = Quaternion.Inverse(transform.rotation) * desiredRotation;
					delta.ToAngleAxis(out remainingAngle,out rotAxis);
					float maxSlew = 3.0f*(Time.timeScale+.01f);
					if (remainingAngle > maxSlew){
						delta = Quaternion.AngleAxis(maxSlew,rotAxis);
						transform.rotation = transform.rotation * delta;
						if (distance < 0.01f)
							distance = 0.011f; // so we don't trigger arrival yet...
					}
					else
					{
						transform.rotation = Quaternion.Lerp(lerpFromRotation,finalRotation,lrp);
					}
				}
				
				if (distance < 0.01f) // was 0.01f, but having occasional race conditions
				{	
					transform.position = m_navMeshAgent.destination; // snap to final
					lerpFromRotation = Quaternion.identity;
					
					m_navMeshAgent.Stop(); // let the final lerp do the node alignment
					m_navMeshAgent.updateRotation = false; // apparently this is needed to keep the position and rotation from being updated. = false; 
					isNavigating = false;
					makingWayFor = null; // if i was getting out of someone's way, i have done that now.
					if ((m_navMeshAgent.pathStatus != NavMeshPathStatus.PathComplete))
					{
						SendMessageUpwards("OnNavigationRequestFailed",SendMessageOptions.DontRequireReceiver); // should really wait for slignment to complete for this
					} else {
						SendMessageUpwards("OnNavigationRequestSucceeded",SendMessageOptions.DontRequireReceiver); // should really wait for alignment to complete for this
					}
					LockMe (); // may destroy the agent
#if DEBUG_NAVIGATION
					UnityEngine.Debug.Log ("NavMeshAgent "+name+" Arrived at "+TargetName);
#endif
					GetComponent<TaskCharacter>().Arrive();
					GetComponent<AnimationManager>().StopWalk(0.5f); // this would be better moved to TaskCharacter.Arrive()
				}
				// see if anyone is in our path
				if (Time.time - lastAvoidCheckTime > avoidCheckInterval)
				{
					if (!CheckForAvoidance()) // this will check every frame while needed
						lastAvoidCheckTime = Time.time;
				}
			}
			else
			{ // is Avoiding, repath when one radius from goal to avoid slowdown ?
				if (distance < m_navMeshAgent.radius*1.0f)
				{
					m_navMeshAgent.SetDestination(finalDestination);
					isNavigating = false;
					isAvoiding = false;
					navRequested = true;
					return;
				}
				else
				{
					// see if anyone ELSE is in our path
					if (Time.time - lastAvoidCheckTime > avoidCheckInterval)
					{
						if (!CheckForAvoidance()) //
							lastAvoidCheckTime = Time.time;
					}
				}
			}
		} 
		else 
		{
			isAvoiding = false;
		}
	}
	public void Execute(InteractionScript callingScript){
//Debug.Log ("XXX"+Time.time+" "+name+type);		
		if ((breakpoint || callingScript.singleStepping)  && callingScript.debug){
			// place a breakpoint here and set breakpoint=true to trap on execute of a particular line of script
			Debug.Log ("Hit Execute Breakpoint for "+name+" of "+callingScript.name);
			InteractionScript.atBreakpoint = callingScript;
			callingScript.waitingForDebugger = true;
			Debug.Break ();
			WaitForDebugger (callingScript);
Debug.Log ("Ran Right Past the Call");
			
		}		
		
		executedBy = callingScript;
/*		moved to Calling script to handle Role mapping
 * 
		if (objectToAffect == null){ // default, or we could try looking up the name again...
			if (objectName != ""){
				objectToAffect = GameObject.Find(executedBy.ResolveArgs(objectName).Replace ("\"",""));
				// we have a problem with two names here, one used by unity, one by the 						
				if (objectToAffect == null){
					objectToAffect = ObjectManager.GetInstance().GetGameObject(objectName);
				}
			}
			else
				objectToAffect = executedBy.myObject; 
		}
*/
		
		if (executedBy != null)
			objectToAffect = executedBy.FindObjectToAffect(this);
		
		
		if (type != actionType.putMessage && objectToAffect != null) // don't need a taskCharacter to send a message...
			taskChar = objectToAffect.GetComponent<TaskCharacter>();
		
		if (!forceExecute){
			if (taskChar != null && taskChar.executingScript != null && taskChar.executingScript != this){
				// this character is already busy, so wait until the current line completes	
				StartCoroutine (ExecuteWhenIdle(callingScript));
				return;
			}
			
			if (taskChar != null){
				taskChar.executingScript = this;
				if (taskChar.actingInScript != null && taskChar.actingInScript != executedBy){// && CanCompleteImmediately()){
					// don't add me, I'll be done before you know it...
				}
				else
				{
				taskChar.actingInScript = executedBy; // this could get cleared by this character doing an executeScript.
					// since we set it, be sure we're in the list of actor objects so we'll be released
					if (!executedBy.actorObjects.Contains(taskChar as ObjectInteraction))
						executedBy.actorObjects.Add (taskChar as ObjectInteraction);
				}
			}
		}
		forceExecute = false;
		
		
		
#if DEBUG_SCRIPTING
		Debug.Log ("ScriptedAction execute "+name);
#endif
		if (breakpoint && callingScript.debug){
			// place a breakpoint here and set breakpoint=true to trap on execute of a particular line of script
			Debug.Log ("Hit Execute Breakpoint for "+name+" of "+callingScript.name);	
		}
		
		if (hasExecuted && executeOnlyOnce){
			error = "already executed";
			OnComplete();	
		}


		characterTaskPending = false;
		waitingForUpdate = false; // a single update call will complete us
		waitingForDialog = false;
		taskReady = false;
		waitingForNav = false;
		waitingForCondition = false;
		ignoreTimeout = false;
		waitingForAnim = false;
		runIndependentUpdates = false;
		trackCameraLookat = false;
		postureChangeStartTime = 0;
		executedBy = callingScript;
		error = "";
		this.enabled = true; // need updates until we are through
		
		// Temporary hack to add any InteractMessage map to the character to avoid an error
		if (objectToAffect != null && 
			type == actionType.putMessage && 
			gameMsgForm.msgType == GameMsgForm.eMsgType.interactMsg){
			// we are going to add this interaction to the objects AllMaps so it doesn't get an error
			ObjectInteraction OI = objectToAffect.GetComponent<ObjectInteraction>();
			if (OI != null)
				OI.AddToAllMaps(gameMsgForm.map.GetMap());
		}
		
		if (preAttributes != "") SetAttributes(objectToAffect,preAttributes);
		
		// can't do this here, need to do it when we use the values, and don't overwrite the original ones!
//		stringParam = SubstituteArgsAndAttributes(stringParam); // update parameter strings with current #args, $attrs
//		stringParam2 = SubstituteArgsAndAttributes(stringParam2);
//		stringParam3 = SubstituteArgsAndAttributes(stringParam3);
//		stringParam4 = SubstituteArgsAndAttributes(stringParam4);
//		attachmentOverride = SubstituteArgsAndAttributes(attachmentOverride);
		
		if (type == actionType.enableInteraction){

			if (objectName == "Dispatcher"){
				// this will cause all interaction tags except the space delimited list to be rejected
				// until an interaction on the list is hit, which then re-enables all interactions.
				// (needed so scripts can use tags to trigger things when running)
				// an empty list will allow all interactions again.
				Dispatcher td = FindObjectOfType<Dispatcher>();
				if (td != null){
					td.LimitInteractions( stringParam, negate, loop );
				}

				OnComplete();
				Cleanup ();
			}
			else
			{
				// look for an ObjectInteraction component on ObjectToAffect
				if (objectToAffect != null){
					if (objectToAffect.GetComponent<ObjectInteraction>() != null){
						ObjectInteraction OI = objectToAffect.GetComponent<ObjectInteraction>();
						OI.Enabled = !negate;
						
						if (ease || texture2D!= null){ //hackfully abuse the 'ease' boolean to force clear the icon texture
							if (ease) OI.iconTexture = null;
							else if (texture2D!= null) OI.iconTexture = texture2D;
						}
					}
					else // adding handling of nav mesh obstacle here... 
					if (objectToAffect.GetComponent<NavMeshObstacle>() != null){
						NavMeshObstacle NMO = objectToAffect.GetComponent<NavMeshObstacle>();
						NMO.enabled = !negate;
					}					
					
					OnComplete();
					Cleanup ();
				}
				else
				{
					error = "no objectInteraction to enable";
					OnComplete();
					Cleanup ();
				}
			}
		}
		if (type == actionType.playAnimation){
			if (objectToAffect != null){
				taskChar = objectToAffect.GetComponent<TaskCharacter>();
				if (taskChar != null){
					taskChar.Animate(stringParam);	
					// figure out if we should wait...  we could wait for the characterAnimState
					if (waitForCompletion){
						waitingForAnim = true;
						animEndTime = -1; // failsafe for hung waiting for anim to end...
						AnimationState ast = taskChar.GetComponent<AnimationManager>().body.animation[stringParam];
						if (ast != null && ast.clip != null)
							animEndTime = Time.time + ast.clip.length + 0.05f;; 
					}
					else
						OnComplete (); 
				}
				else
				{
					// handle ?speed= ?time= ?wieght=
					string[] p = stringParam.Split ('?');
					string animationName = p[0];
					
					float animSpeed = 1; // for overrideing defaults
					float animWeight = 1;
					float animTime = 0;
					
					int start=1;
					// process speed=  weight= time= possibly mixing transform...
					while (start < p.Length){
						if (p.Length > start && p[start].ToLower().Contains("speed=")){
							string[] q = p[start].Split('=');
							float.TryParse(q[1],out animSpeed);
						}
						if (p.Length > start && p[start].ToLower().Contains("weight=")){
							string[] q = p[start].Split('=');
							float.TryParse(q[1],out animWeight);
						}
						if (p.Length > start && p[start].ToLower().Contains("time=")){
							string[] q = p[start].Split('=');
							float.TryParse(q[1],out animTime);
						}
						start++;
					}

					if (objectToAffect.animation != null){
						if (animTime == 0)
							objectToAffect.animation.Rewind(animationName);
						if (animTime > 0) objectToAffect.animation[animationName].time = animTime;
						objectToAffect.animation[animationName].speed = animSpeed;
						objectToAffect.animation[animationName].weight = animWeight;
						objectToAffect.animation.clip = objectToAffect.animation[animationName].clip;
						objectToAffect.animation.Play();

						if (waitForCompletion)
							waitingForAnim = true;
						else
							OnComplete ();
					}
					
				}
			}
			else
			{
				error = "no object to play animation on";
				OnComplete();
				Cleanup ();
			}
		}
		if (type == actionType.playAudio){
			// object to affect should have an audio source
			AudioSource src = null;
			if (objectToAffect != null)
				src = objectToAffect.GetComponent<AudioSource>();
			if (src == null)
				src = objectToAffect.AddComponent<AudioSource>() as AudioSource;
		
			if (src != null){
				float timeToWait = fadeLength;
				if (audioClip == null){

					// find the audio clip, looking thru the sound map for this character?

					if (stringParam != ""){
						VoiceMap vm = VoiceMgr.GetInstance().Find(objectToAffect.name, stringParam);
						if (vm != null){
							vm.Clip = SoundMgr.GetInstance().GetClip(vm.Audio);
							if (vm.Clip != null) timeToWait += vm.Clip.length;
							VoiceMgr.GetInstance().Play (objectToAffect.name, stringParam);	
							if (stringParam2 != "" && taskChar != null && vm.Clip != null)
								taskChar.LookAt(stringParam2, Time.time + vm.Clip.length);
						}
						else{
							audioClip = SoundMgr.GetInstance().Get(stringParam);
						}
					}
				}
				if (audioClip != null){ // will still be null if we sent this to the voice manager
					src.clip = audioClip;
					src.Play();
					timeToWait += audioClip.length;
					if (stringParam2 != "" && taskChar != null)
						taskChar.LookAt(stringParam2, Time.time + audioClip.length);
				}
				
				
				if (waitForCompletion)
					StartCoroutine(CompleteAfterDelay (timeToWait));
				else {
					OnComplete();
					Cleanup ();
				}
			}
			else
			{
				error = "no audiosource for playAudio";
				OnComplete();
			}
		}
		if (type == actionType.putMessage){
			// hack to avoid 'I'm too busy messages... 
			if (taskChar != null)
				taskChar.executingScript = null;
			StartCoroutine(SendMessageAfterDelay(fadeLength));
		}
		if (type == actionType.move){ // 
			// lets handle the camera move first:
			if (moveTo == null){ // translate the name, if presesnt
				if (moveToName != "" && GameObject.Find(moveToName)!= null ){
					moveTo = GameObject.Find(moveToName).transform;
				}
			}
			
			CameraLERP cameraLERP = objectToAffect.GetComponent<CameraLERP>();
			if (cameraLERP != null){
				// strangely in Unity, we're not allowed to create new Transforms, so we have to make a dummy
				if (moveTo != null){
					if (offset == Vector3.zero){
						// assume this is a return to the spline
						// reset the camera rail controller so we go to the starting position...
				//		CameraRailCoordinator crc = FindObjectOfType<CameraRailCoordinator>();
				//		if (crc != null)
				//			crc.Reset();

						//
						cameraLERP.MoveTo(moveTo, fadeLength,true,false, 0);
						trackCameraLookat = true;
						if (!waitForCompletion) runIndependentUpdates = true;
						StartCoroutine( EndTrackCameraLookat(fadeLength));
						if (!waitForCompletion) OnComplete ();
						return;
					}
					else
					{
						dummyGO = new GameObject("dummyGO");
						dummyGO.transform.position = moveTo.position 
								+ offset.x*dummyGO.transform.forward
								+ offset.y*dummyGO.transform.up
								+ offset.z*dummyGO.transform.right;
						dummyGO.transform.LookAt(moveTo);
						cameraLERP.MoveTo(dummyGO.transform, fadeLength,true,true, 0);	
					}
				}
				else
				{
					if (fadeLength <= 0)
						cameraLERP.Return(); // snap back
					else
					{
						GameObject dummyGO = new GameObject("dummyGO");
						dummyGO.transform.position = cameraLERP.oldWorldPos; 
						dummyGO.transform.rotation = cameraLERP.oldWorldRot;	
						cameraLERP.MoveTo(dummyGO.transform, fadeLength,true,false, 0);
					}
				}
				//Destroy (dummyGO);  destroy this later on Completed
				if (waitForCompletion && fadeLength > 0)
					StartCoroutine(CompleteAfterDelay (fadeLength));
				else {
					OnComplete();
					//Cleanup ();
				}
			}
			else
			{
				// if the moveTo NAME is a valid Node Name, we can use the TaskCharacter to move there
				taskChar = objectToAffect.GetComponent<TaskCharacter>();
				if (taskChar != null){
//					bool bResult = 
					taskChar.IsInPosition (moveTo.name); // this should start off the nav
				// lets see if we have something with a NavMeshAgentWrapper...
				//	navWrapper = objectToAffect.GetComponent<NavMeshAgentWrapper>();
				//	if (navWrapper != null){ // lets ignore the offset for now...
				//			navWrapper.MoveToGameObject(moveTo.gameObject,2.0f);
					if (waitForCompletion){
						navStartTime = Time.realtimeSinceStartup; // we may want to time out
						waitingForNav = true; 
						return;
					}
					else{
						runIndependentUpdates = true;
						pingTaskCharacter = true;
						OnComplete();
					}
				//	}
				}
				else
				{
					error = "move only implemented for camera, no cameraLERP found";
					OnComplete();	
				}
			}
		}
		
		if (type == actionType.fade){ // 
			if (objectToAffect == null){
				Debug.LogWarning("Null object "+objectName+" for fade by "+name);
				OnComplete();
				Cleanup();
				return;				
			}
			// if the thing is a the GUIManager then fade it
			GUIManager gm = objectToAffect.GetComponent<GUIManager>();
			// test it					
			if (gm != null) {
					gm.SetFadeCurtain(desiredColor.a, fadeLength);
				OnComplete();
				Cleanup ();
				return;
			}
			// we need to have an object with a renderer.
			if (objectToAffect != null && objectToAffect.renderer != null){
				
			// if string param has something, look for a resource by that name that is a mesh or material to swap in
				
			Material newMaterial = null;
//			Mesh newMesh = null;
			if (stringParam != ""){
				newMaterial = Resources.Load(stringParam) as Material;
//				newMesh = Resources.Load(stringParam) as Mesh;
			}
			
			// fade can be an instant change, or take some time.
			// desired color should override desired alpha
			if (stringParam=="current"){
				// should check new material and use it's color if provided
				desiredColor = objectToAffect.renderer.material.color;
				desiredColor.a = desiredAlpha;
			}
			desiredColor.a = desiredAlpha;
			
			if (fadeLength > 0){
				// get components
				// if the thing has a color changer, lets make use of that.
				ColorChanger cc = objectToAffect.GetComponent<ColorChanger>();

				if (cc != null){
					cc.ChangeColor(desiredColor, fadeLength);
				}
				else
				{
//					fadeBeginTime = Time.time;
//					fadeBeginColor = objectToAffect.renderer.material.color;
					if (desiredAlpha > 0){
						objectToAffect.renderer.enabled = true;
						// temporarily just jam the final result until the fade interpolate is in place	
						objectToAffect.renderer.material.color = desiredColor;	
					}
					// if the final alpha is zero, then set the alpha, and turn off the renderer
					else
					{
						objectToAffect.renderer.enabled = false;
						objectToAffect.renderer.material.color = desiredColor;							
					}	
				}
			}
			else { // instant fade
				if (newMaterial != null)
					renderer.material = newMaterial;
				// if final alpha is > 0, turn the renderer on and set the alpha
				if (desiredAlpha > 0){
					objectToAffect.renderer.enabled = true;
					objectToAffect.renderer.material.color = desiredColor;	
				}
				// if the final alpha is zero, then set the alpha, and turn off the renderer
				else
				{
					objectToAffect.renderer.enabled = false;
					objectToAffect.renderer.material.color = desiredColor;							
				}
			}
			}
			else
			{ // missing object or renderer
				error = "Fade has no object with renderer specified";
			}
			OnComplete();
			Cleanup ();
		}
		
		if (type == actionType.ifThenElse){ // 
			
			BaseObject bob = null;
			if (objectToAffect != null && objectToAffect.GetComponent<BaseObject>() != null)
				bob = objectToAffect.GetComponent<BaseObject>();
			if (bob != null){
				// build a binaryExpressionNode out of the string for our testEntity and evaluate.
				
				// perform any arg substitutions
				string newString = executedBy.ResolveArgs(stringParam);
				BinaryExpressionNode condition = BinaryExpressionNode.BuildTree(newString);
				if (condition.Evaluate(bob))
					executedBy.nextLineLabel = ""; // just go on to the next statement
				else
					executedBy.nextLineLabel = "else"; // this will find either the next 'else' block or the next 'endIfThenElse' block
			}
			else
			{
				error = "no baseObject for ifThenElse to test";
			}
//			executedBy.nestingDepth += 1;
			OnComplete();
			Cleanup ();
		}
		
		if (type == actionType.executeScript){ // our execution will be stacked and we will pend until this script completes
			if (scriptToExecute == null && stringParam2 != null && stringParam2 != ""){
				// First, look for a script on the character running this interaction
				if (taskChar != null){
					ScriptedObject tcso = taskChar.GetComponent<ScriptedObject>();
					if (tcso!=null){
						foreach (InteractionScript tcis in tcso.scripts){
							if (tcis.name == stringParam2){
								scriptToExecute = tcis;
								break;
							}
						}
					}
				}
				
				if (scriptToExecute == null){
					// try finding the named game object and look for an interaction script there
					GameObject isGO = GameObject.Find(stringParam2);
					if (isGO != null)
						scriptToExecute = isGO.GetComponent<InteractionScript>();
				}
			}
			
			if (scriptToExecute == null){
				
				Debug.LogError("scriptedAction could not find script to execute at "+name+executedBy.name);
			
				OnComplete ();
				Cleanup ();
			}
			
			if (waitForCompletion){ // run this as a subroutine, continuing when it's done
				//build a string with our script's args and add to stringParam args...
				if (taskChar != null) taskChar.executingScript = null;  // need to clear this for the next scrip
				executedBy.ExecuteScript(scriptToExecute, executedBy.ResolveArgs(stringParam)+" trigger="+name, objectToAffect, ease);
				// yield until we get an update. which will complete us.  we HAVE to wait, no multi threading support yet.
				waitingForUpdate = true;
			}
			else
			{ // don't wait for completion, so we will JUMP and not return to this line
				if (taskChar != null) taskChar.executingScript = null;  // need to clear this for the next scrip
				executedBy.QueueScript(scriptToExecute, executedBy.ResolveArgs(stringParam)+" trigger="+name, objectToAffect, ease);
				// yield until we get an update. which will complete us.  we HAVE to wait, no multi threading support yet.
				executedBy.nextLineLabel = "abort"; // terminate this script
				error="abort";
				OnComplete();
				Cleanup ();
			}
		}
		
		if (type == actionType.queueScript){
			// no script and loop set means flush all scripts from the queue
			if (scriptToExecute == null && loop && (stringParam2 == null || stringParam2 == "")){
				// remove all scripts that are not currently on the stack from the queue
				executedBy.caller.FlushScriptQueue();
				
				OnComplete();
				Cleanup ();
				return;				
			}
			
			if (scriptToExecute == null && stringParam2 != null && stringParam2 != ""){
				// try finding the named game object and look for an interaction script there
				GameObject isGO = GameObject.Find(stringParam2);
				if (isGO != null)
					scriptToExecute = isGO.GetComponent<InteractionScript>();
			}			
			if (scriptToExecute != null)
				executedBy.QueueScript(scriptToExecute, executedBy.ResolveArgs(stringParam)+" trigger="+name, objectToAffect, ease);
			else
				Debug.LogError("FAILED TO FIND script named \""+stringParam2+"\"");
			OnComplete();
			Cleanup ();
			return;	
		}
			
		if (type == actionType.wait){ // we ignore wait for completion on this one...
			// set the HoldPosition flag if requested
			if (loop){
				NavMeshAgentWrapper w = objectToAffect.GetComponent<NavMeshAgentWrapper>();	
				if (w != null)
					w.HoldPosition(true); // if there is no condition, holdPosition will stick till the next character task
			}
			// specifying wait 0 and delay = #delay lets you pass a delay into the script.
			if (fadeLength==0 && stringParam.ToLower().Contains("delay=")){
				string delayString = SubstituteArgsAndAttributes(stringParam);
				if (!float.TryParse(delayString.Replace("delay=",""),out fadeLength)){
					Debug.LogWarning("bad delay time in scripted action "+ name + stringParam);
					OnComplete();
					Cleanup ();
				}
				else {
					StartCoroutine(CompleteAfterDelay (fadeLength));
					return;
				}
			}
			// let's see about waiting for a TAG:NAME 
			if (stringParam.Contains(":") && !stringParam.Contains ("=")){ // this could be better at excluding other things that contain ":"
				// assume this thing is a tag, and post a listener
				//GUIManager.GetInstance().AddInteractCallback(null,myInteractCallback);
				Brain.GetInstance().AddCallback(myInteractCallback);
				// fadelength should be a timeout here if > 0
				if (fadeLength > 0)
					StartCoroutine(CompleteAfterDelay (fadeLength));
			}
			else
			{
				if (stringParam == "" || stringParam == null){
					StartCoroutine(CompleteAfterDelay (fadeLength));
				}
				else
				{
					waitingForCondition = true;
					conditionNode = BinaryExpressionNode.BuildTree(stringParam);
					if (fadeLength > 0)
						StartCoroutine(CompleteAfterDelay (fadeLength)); // this starts a timeout
				}
			}
		}
		
		if (type == actionType.characterTask){ // 
			taskChar = objectToAffect.GetComponent<TaskCharacter>();
			nmaWrapper = objectToAffect.GetComponent<NavMeshAgentWrapper>();
			if (taskChar != null){ 
				taskChar.Init(); // clears flags
				taskChar.executingScript = this; // restore this flag
				// overload 'ease' for random pathnode/animation 
				if (moveToName.ToLower()=="random"){
					ease=true;
					moveToName = SceneNode.GetRandomUnlockedNode().name; // this could return a null, BOOM!
				}
				else
				{
					ease=false;
				}
				
				
				StartCoroutine(CharacterTaskAfterDelay(fadeLength));
				if (!waitForCompletion){
					runIndependentUpdates = true;
					OnComplete ();
				}
			}
		}
		if (type == actionType.attach){ // 
			TaskCharacter tc = objectToAffect.GetComponent<TaskCharacter>();
			if (negate){ // this is a detach, which leaves the object loose at the top level of the hierarchy.
				if (tc != null){
					tc.Detach(SubstituteArgsAndAttributes(attachmentOverride));
				}
			}
			else
			{	// this is an attach, and it's usually better to attach to a new parent than to just detach.
				bool attachingToTcBone = true;
				if (tc != null){
					// if there's an attachment override, and you can find the object and a bone,
					// then place the object at the bone plus offset location
					string substituted = attachmentOverride;
					if (attachmentOverride != "" && attachmentOverride.Contains(" ")){
						string[]p = attachmentOverride.Split (' ');
						GameObject targetObject = GameObject.Find (SubstituteArgsAndAttributes(p[0]).Replace ("\"",""));
						Transform parentBone = tc.GetComponent<AnimationManager>().GetBone(p[1].Replace ("\"",""));
						attachingToTcBone = (parentBone != null);
						if (targetObject == null){
							Debug.LogError(executedBy.name+": "+name+" Script Attachment found no target object in "+attachmentOverride);
							OnComplete();
							Cleanup ();
							return;
						}
						if (!attachingToTcBone){
							// name is not a bone, see if there's a game object by this name
							GameObject parentObject = GameObject.Find (SubstituteArgsAndAttributes(p[1]).Replace ("\"",""));
							if (parentObject != null)
								parentBone = parentObject.transform;
							tc.Detach(targetObject.name); // remove this from the attached Objects list...
						}
						substituted = targetObject.name+" "+p[1].Replace ("\"","");
						if (offset != new Vector3(-1,-1,-1)){
							if (targetObject != null && parentBone != null){
								// if there's a delay, then we can do the lerp in a co-routine 
								if (fadeLength > 0){
									StartCoroutine (AttachAfterDelay(targetObject,parentBone,tc,substituted,attachingToTcBone));
									return;  // don't cleanup or complete until after delayed lerp
								}
								else
								{
									targetObject.transform.position = parentBone.TransformPoint(offset);//position+offset;
									targetObject.transform.rotation = parentBone.rotation*Quaternion.Euler(orientation);
									if (!attachingToTcBone) targetObject.transform.parent = parentBone;
								}
							}
						}
						else
						{  // performing attach using current position
							if (!attachingToTcBone) targetObject.transform.parent = parentBone;
						}
					}
					if (attachingToTcBone)
						tc.Attach(substituted);	
				}
			}
			OnComplete();
			Cleanup ();
		}
		if (type == actionType.spawn){
			GameObject newObject = Instantiate(Resources.Load(stringParam), 
								objectToAffect.transform.position, objectToAffect.transform.rotation)  as GameObject;
			newObject.name = SubstituteArgsAndAttributes(stringParam2);
			if (stringParam3 != ""){
				GameObject newParent = GameObject.Find (stringParam3);
				if (newParent != null){
					newObject.transform.parent = newParent.transform;
					newObject.transform.localPosition = offset;
				}
			}
			executedBy.args["spawnedname"]=newObject.name;
			OnComplete();
			Cleanup ();
		}
		if (type == actionType.destroy){
			Destroy(objectToAffect);
			OnComplete();
			Cleanup ();
		}
		if (type == actionType.unityMessage){ // 
			if (objectToAffect != null)
				objectToAffect.SendMessage(stringParam,stringParam2);
			OnComplete();
			Cleanup ();
		}
		if (type == actionType.lockPosition){
			if (negate){
				NavMeshAgentWrapper w = objectToAffect.GetComponent<NavMeshAgentWrapper>();	
				if (w != null)
					w.LockPosition(false); 
				ScriptedObject so = objectToAffect.GetComponent<ScriptedObject>();
				if (so != null)
					so.executePriorityLock = -1;
			}
			else
			{
				NavMeshAgentWrapper w = objectToAffect.GetComponent<NavMeshAgentWrapper>();	
				if (w != null)
					w.LockPosition(true);
				if (stringParam != ""){
					int lockPriority;
					if (int.TryParse(stringParam,out lockPriority)){
						ScriptedObject so = objectToAffect.GetComponent<ScriptedObject>();
						if (so != null)
							so.executePriorityLock = lockPriority;
					}
				}
				// test unlocking any nodes we have locked, so they are not blocking.
				// this is specifically for BVM, but might be good overall.
				SceneNode.UnlockLocation(objectToAffect.transform.position,0.5f); // radius is completely arbitrary 0.44f is probably a good value.
			}
			OnComplete();
			Cleanup ();
			
		}
		if (type == actionType.goToLine){ // 
			executedBy.nextLineLabel = stringParam; // untested, and very scary
			OnComplete();
			Cleanup ();
		}
		if (type == actionType.setIKTarget){ //
			TaskCharacter tc = objectToAffect.GetComponent<TaskCharacter>();
			if (tc != null){
				IKArmController ctlr = tc.IKArmRight;
				if (stringParam.ToLower().Contains ("left"))
					ctlr = tc.IKArmLeft;
				
				if ((moveToName == null) || moveToName == ""){
					// we are clearing the target
					ctlr.target = null;
				}
				else
				{	
					GameObject targetGo = GameObject.Find(moveToName);
					if (targetGo != null){
						ctlr.target = targetGo.transform;
						HandPoser poser = targetGo.GetComponent<HandPoser>();
						if (poser != null)
							poser.Setup(ctlr.hand);
					}
				}
				ctlr.blendTime = fadeLength;

				ctlr.offset = offset;
				ctlr.orientation = Quaternion.Euler(orientation);
				if (stringParam2 == null || stringParam2 == "") stringParam2 = "0";
				float releaseTime = 0;
				float.TryParse(stringParam2, out releaseTime);
				ctlr.releaseTime = releaseTime;
			}
			
			OnComplete(); // we'll worry about wait for completion later  TODO
			Cleanup ();
		}
	}