1  
     8  
     9  
    34  
    35  import caurina.transitions.Equations;
    36  import caurina.transitions.AuxFunctions;
    37  import caurina.transitions.SpecialProperty;
    38  import caurina.transitions.SpecialPropertyModifier;
    39  import caurina.transitions.SpecialPropertySplitter;
    40  import caurina.transitions.TweenListObj;
    41  import caurina.transitions.PropertyInfoObj;
    42  
    43  class caurina.transitions.Tweener {
    44  
    45  	private static var _engineExists:Boolean = false;		
    46  	private static var _inited:Boolean = false;				
    47  	private static var _currentTime:Number;					
    48  	private static var _currentTimeFrame:Number;			
    49  
    50  	private static var _tweenList:Array;					
    51  
    52  	private static var _timeScale:Number = 1;				
    53  
    54  	private static var _transitionList:Object;				
    55  	private static var _specialPropertyList:Object;			
    56  	private static var _specialPropertyModifierList:Object;	
    57  	private static var _specialPropertySplitterList:Object;	
    58  
    59  
    60  	
    63  	public function Tweener () {
    64  		trace ("Tweener is an static class and should not be instantiated.");
    65  	}
    66  
    67  
    68  	
    69  	
    70  
    71  	
    93  	public static function addTween (p_scopes:Object, p_parameters:Object):Boolean {
    94  		if (p_scopes == undefined) return false;
    95  
    96  		var i:Number, j:Number, istr:String;
    97  
    98  		var rScopes:Array; 
    99  		if (p_scopes instanceof Array) {
   100  			
   101  			rScopes = p_scopes.concat();
   102  		} else {
   103  			
   104  			rScopes = [p_scopes];
   105  		}
   106  
   107          
   108  		var p_obj:Object = TweenListObj.makePropertiesChain(p_parameters);
   109  
   110  		
   111  		if (!_inited) init();
   112  		if (!_engineExists || _root[getControllerName()] == undefined) startEngine(); 
   113  
   114  		
   115  		var rTime:Number = (isNaN(p_obj.time) ? 0 : p_obj.time); 
   116  		var rDelay:Number = (isNaN(p_obj.delay) ? 0 : p_obj.delay); 
   117  
   118  		
   119  		var rProperties:Object = new Object(); 
   120  		var restrictedWords:Object = {time:true, delay:true, useFrames:true, skipUpdates:true, transition:true, transitionParams:true, onStart:true, onUpdate:true, onComplete:true, onOverwrite:true, onError:true, rounded:true, onStartParams:true, onUpdateParams:true, onCompleteParams:true, onOverwriteParams:true, onStartScope:true, onUpdateScope:true, onCompleteScope:true, onOverwriteScope:true, onErrorScope:true, quickAdd:true};
   121  		var modifiedProperties:Object = new Object();
   122  		for (istr in p_obj) {
   123  			if (!restrictedWords[istr]) {
   124  				
   125  				if (_specialPropertySplitterList[istr] != undefined) {
   126  					
   127  					var splitProperties:Array = _specialPropertySplitterList[istr].splitValues(p_obj[istr], _specialPropertySplitterList[istr].parameters);
   128  					for (i = 0; i < splitProperties.length; i++) {
   129  						if (_specialPropertySplitterList[splitProperties[i].name] != undefined) {
   130  							var splitProperties2:Array = _specialPropertySplitterList[splitProperties[i].name].splitValues(splitProperties[i].value, _specialPropertySplitterList[splitProperties[i].name].parameters);
   131  							for (j = 0; j < splitProperties2.length; j++) {
   132  								rProperties[splitProperties2[j].name] = {valueStart:undefined, valueComplete:splitProperties2[j].value, arrayIndex:splitProperties2[j].arrayIndex, isSpecialProperty:false};
   133  							}
   134  						} else {
   135  							rProperties[splitProperties[i].name] = {valueStart:undefined, valueComplete:splitProperties[i].value, arrayIndex:splitProperties[i].arrayIndex, isSpecialProperty:false};
   136  						}
   137  					}
   138  				} else if (_specialPropertyModifierList[istr] != undefined) {
   139  					
   140  					var tempModifiedProperties:Array = _specialPropertyModifierList[istr].modifyValues(p_obj[istr]);
   141  					for (i = 0; i < tempModifiedProperties.length; i++) {
   142  						modifiedProperties[tempModifiedProperties[i].name] = {modifierParameters:tempModifiedProperties[i].parameters, modifierFunction:_specialPropertyModifierList[istr].getValue};
   143  					}
   144  				} else {
   145  					
   146  					rProperties[istr] = {valueStart:undefined, valueComplete:p_obj[istr]};
   147  				}
   148  			}
   149  		}
   150  
   151  		
   152  		for (istr in rProperties) {
   153  			if (_specialPropertyList[istr] != undefined) {
   154  				rProperties[istr].isSpecialProperty = true;
   155  			} else {
   156  				if (rScopes[0][istr] == undefined) {
   157  					printError("The property '" + istr + "' doesn't seem to be a normal object property of " + rScopes[0].toString() + " or a registered special property.");
   158  				}
   159  			}
   160  		}
   161  
   162  		
   163  		for (istr in modifiedProperties) {
   164  			if (rProperties[istr] != undefined) {
   165  				rProperties[istr].modifierParameters = modifiedProperties[istr].modifierParameters;
   166  				rProperties[istr].modifierFunction = modifiedProperties[istr].modifierFunction;
   167  			}
   168  			
   169  		}
   170  		
   171  		var rTransition:Function; 
   172  
   173  		if (typeof p_obj.transition == "string") {
   174  			
   175  			var trans:String = p_obj.transition.toLowerCase();
   176  			rTransition = _transitionList[trans];
   177  		} else {
   178  			
   179  			rTransition = p_obj.transition;
   180  		}
   181  		if (rTransition == undefined) rTransition = _transitionList["easeoutexpo"];
   182  
   183  		var nProperties:Object;
   184  		var nTween:TweenListObj;
   185  		var myT:Number;
   186  
   187  		for (i = 0; i < rScopes.length; i++) {
   188  			
   189  			nProperties = new Object();
   190  			for (istr in rProperties) {
   191  				nProperties[istr] = new PropertyInfoObj(rProperties[istr].valueStart, rProperties[istr].valueComplete, rProperties[istr].valueComplete, rProperties[istr].arrayIndex, {}, rProperties[istr].isSpecialProperty, rProperties[istr].modifierFunction, rProperties[istr].modifierParameters);
   192  			}
   193  
   194  			if (p_obj.useFrames == true) {
   195  				nTween = new TweenListObj(
   196  						rScopes[i],
   197  						_currentTimeFrame + (rDelay / _timeScale),
   198  						_currentTimeFrame + ((rDelay + rTime) / _timeScale),
   199  						true,
   200  						rTransition,
   201  											p_obj.transitionParams
   202  				);
   203  			} else {
   204  				nTween = new TweenListObj(
   205  						rScopes[i],
   206  						_currentTime + ((rDelay * 1000) / _timeScale),
   207  						_currentTime + (((rDelay * 1000) + (rTime * 1000)) / _timeScale),
   208  						false,
   209  						rTransition,
   210  											p_obj.transitionParams
   211  				);
   212  			}
   213  
   214  			nTween.properties			=	nProperties;
   215  			nTween.onStart				=	p_obj.onStart;
   216  			nTween.onUpdate				=	p_obj.onUpdate;
   217  			nTween.onComplete			=	p_obj.onComplete;
   218  			nTween.onOverwrite			=	p_obj.onOverwrite;
   219  			nTween.onError              =   p_obj.onError;
   220  			nTween.onStartParams		=	p_obj.onStartParams;
   221  			nTween.onUpdateParams		=	p_obj.onUpdateParams;
   222  			nTween.onCompleteParams		=	p_obj.onCompleteParams;
   223  			nTween.onOverwriteParams	=	p_obj.onOverwriteParams;
   224  			nTween.onStartScope			=	p_obj.onStartScope;
   225  			nTween.onUpdateScope		=	p_obj.onUpdateScope;
   226  			nTween.onCompleteScope		=	p_obj.onCompleteScope;
   227  			nTween.onOverwriteScope		=	p_obj.onOverwriteScope;
   228  			nTween.onErrorScope			=	p_obj.onErrorScope;
   229  			nTween.rounded				=	p_obj.rounded;
   230  			nTween.skipUpdates			=	p_obj.skipUpdates;
   231  
   232  			
   233  			if (!p_obj.quickAdd) removeTweensByTime(nTween.scope, nTween.properties, nTween.timeStart, nTween.timeComplete);
   234  
   235  			
   236  			_tweenList.push(nTween);
   237  
   238  			
   239  			if (rTime == 0 && rDelay == 0) {
   240  				myT = _tweenList.length-1;
   241  				updateTweenByIndex(myT);
   242  				removeTweenByIndex(myT);
   243  			}
   244  		}
   245  
   246  		return true;
   247  	}
   248  
   249  	
   250  	
   251  
   252  	
   267  	public static function addCaller (p_scopes:Object, p_parameters:Object):Boolean {
   268  		if (p_scopes == undefined) return false;
   269  
   270  		var i:Number;
   271  
   272  		var rScopes:Array; 
   273  		if (p_scopes instanceof Array) {
   274  			
   275  			rScopes = p_scopes.concat();
   276  		} else {
   277  			
   278  			rScopes = [p_scopes];
   279  		}
   280  
   281  		var p_obj:Object = p_parameters;
   282  
   283  		
   284  		if (!_inited) init();
   285  		if (!_engineExists || _root[getControllerName()] == undefined) startEngine(); 
   286  
   287  		
   288  		var rTime:Number = (isNaN(p_obj.time) ? 0 : p_obj.time); 
   289  		var rDelay:Number = (isNaN(p_obj.delay) ? 0 : p_obj.delay); 
   290  
   291  		var rTransition:Function; 
   292  		if (typeof p_obj.transition == "string") {
   293  			
   294  			var trans:String = p_obj.transition.toLowerCase();
   295  			rTransition = _transitionList[trans];
   296  		} else {
   297  			
   298  			rTransition = p_obj.transition;
   299  		}
   300  		if (rTransition == undefined) rTransition = _transitionList["easeoutexpo"];
   301  
   302  		var nTween:TweenListObj;
   303  		var myT:Number;
   304  		for (i = 0; i < rScopes.length; i++) {
   305  
   306  			if (p_obj.useFrames == true) {
   307  				nTween = new TweenListObj(
   308  						rScopes[i],
   309  						_currentTimeFrame + (rDelay / _timeScale),
   310  						_currentTimeFrame + ((rDelay + rTime) / _timeScale),
   311  						true,
   312  						rTransition,
   313  											p_obj.transitionParams
   314  				);
   315  			} else {
   316  				nTween = new TweenListObj(
   317  						rScopes[i],
   318  						_currentTime + ((rDelay * 1000) / _timeScale),
   319  						_currentTime + (((rDelay * 1000) + (rTime * 1000)) / _timeScale),
   320  						false,
   321  						rTransition,
   322  											p_obj.transitionParams
   323  				);
   324  			}
   325  
   326  			nTween.properties			=	undefined;
   327  			nTween.onStart				=	p_obj.onStart;
   328  			nTween.onUpdate				=	p_obj.onUpdate;
   329  			nTween.onComplete			=	p_obj.onComplete;
   330  			nTween.onOverwrite			=	p_obj.onOverwrite;
   331  			nTween.onStartParams		=	p_obj.onStartParams;
   332  			nTween.onUpdateParams		=	p_obj.onUpdateParams;
   333  			nTween.onCompleteParams		=	p_obj.onCompleteParams;
   334  			nTween.onOverwriteParams	=	p_obj.onOverwriteParams;
   335  			nTween.onStartScope			=	p_obj.onStartScope;
   336  			nTween.onUpdateScope		=	p_obj.onUpdateScope;
   337  			nTween.onCompleteScope		=	p_obj.onCompleteScope;
   338  			nTween.onOverwriteScope		=	p_obj.onOverwriteScope;
   339  			nTween.onErrorScope			=	p_obj.onErrorScope;
   340  			nTween.isCaller				=	true;
   341  			nTween.count				=	p_obj.count;
   342  			nTween.waitFrames			=	p_obj.waitFrames;
   343  
   344  			
   345  			_tweenList.push(nTween);
   346  
   347  			
   348  			if (rTime == 0 && rDelay == 0) {
   349  				myT = _tweenList.length-1;
   350  				updateTweenByIndex(myT);
   351  				removeTweenByIndex(myT);
   352  			}
   353  		}
   354  
   355  		return true;
   356  	}
   357  
   358  	
   367  	public static function removeTweensByTime (p_scope:Object, p_properties:Object, p_timeStart:Number, p_timeComplete:Number):Boolean {
   368  		var removed:Boolean = false;
   369  		var removedLocally:Boolean;
   370  
   371  		var i:Number;
   372  		var tl:Number = _tweenList.length;
   373  		var pName:String;
   374  
   375  		for (i = 0; i < tl; i++) {
   376  			if (p_scope == _tweenList[i].scope) {
   377  				
   378  				if (p_timeComplete > _tweenList[i].timeStart && p_timeStart < _tweenList[i].timeComplete) {
   379  					
   380  					removedLocally = false;
   381  					for (pName in _tweenList[i].properties) {
   382  						if (p_properties[pName] != undefined) {
   383  							
   384  							
   385  							if (_tweenList[i].onOverwrite != undefined) {
   386  								var eventScope:Object = _tweenList[i].onOverwriteScope != undefined ? _tweenList[i].onOverwriteScope : _tweenList[i].scope;
   387  								try {
   388  									_tweenList[i].onOverwrite.apply(eventScope, _tweenList[i].onOverwriteParams);
   389  								} catch(e:Error) {
   390  									handleError(_tweenList[i], e, "onOverwrite");
   391  								}
   392  							}
   393  							_tweenList[i].properties[pName] = undefined;
   394  							delete _tweenList[i].properties[pName];
   395  							removedLocally = true;
   396  							removed = true;
   397  						}
   398  					}
   399  					if (removedLocally) {
   400  						
   401  						if (AuxFunctions.getObjectLength(_tweenList[i].properties) == 0) removeTweenByIndex(i);
   402  					}
   403  				}
   404  			}
   405  		}
   406  
   407  		return removed;
   408  	}
   409  
   410  	
   417  	public static function removeTweens (p_scope:Object):Boolean {
   418  		
   419  		var properties:Array = new Array();
   420  		var i:Number;
   421  		for (i = 1; i < arguments.length; i++) {
   422  			if (typeof(arguments[i]) == "string" && !AuxFunctions.isInArray(arguments[i], properties)) properties.push(arguments[i]);
   423  		}
   424  		
   425  		return affectTweens(removeTweenByIndex, p_scope, properties);
   426  	}
   427  
   428  	
   433  	public static function removeAllTweens ():Boolean {
   434  		var removed:Boolean = false;
   435  		var i:Number;
   436  		for (i = 0; i < _tweenList.length; i++) {
   437  			removeTweenByIndex(i);
   438  			removed = true;
   439  		}
   440  		return removed;
   441  	}
   442  
   443  	
   450  	public static function pauseTweens (p_scope:Object):Boolean {
   451  		
   452  		var properties:Array = new Array();
   453  		var i:Number;
   454  		for (i = 1; i < arguments.length; i++) {
   455  			if (typeof(arguments[i]) == "string" && !AuxFunctions.isInArray(arguments[i], properties)) properties.push(arguments[i]);
   456  		}
   457  		
   458  		return affectTweens(pauseTweenByIndex, p_scope, properties);
   459  	}
   460  
   461  	
   466  	public static function pauseAllTweens ():Boolean {
   467  		var paused:Boolean = false;
   468  		var i:Number;
   469  		for (i = 0; i < _tweenList.length; i++) {
   470  			pauseTweenByIndex(i);
   471  			paused = true;
   472  		}
   473  		return paused;
   474  	}
   475  
   476  	
   483  	public static function resumeTweens (p_scope:Object):Boolean {
   484  		
   485  		var properties:Array = new Array();
   486  		var i:Number;
   487  		for (i = 1; i < arguments.length; i++) {
   488  			if (typeof(arguments[i]) == "string" && !AuxFunctions.isInArray(arguments[i], properties)) properties.push(arguments[i]);
   489  		}
   490  		
   491  		return affectTweens(resumeTweenByIndex, p_scope, properties);
   492  	}
   493  
   494  	
   499  	public static function resumeAllTweens ():Boolean {
   500  		var resumed:Boolean = false;
   501  		var i:Number;
   502  		for (i = 0; i < _tweenList.length; i++) {
   503  			resumeTweenByIndex(i);
   504  			resumed = true;
   505  		}
   506  		return resumed;
   507  	}
   508  
   509  	
   517  	private static function affectTweens (p_affectFunction:Function, p_scope:Object, p_properties:Array):Boolean {
   518  		var affected:Boolean = false;
   519  		var i:Number;
   520  
   521  		if (!_tweenList) return false;
   522  
   523  		for (i = 0; i < _tweenList.length; i++) {
   524  			if (_tweenList[i].scope == p_scope) {
   525  				if (p_properties.length == 0) {
   526  					
   527  					p_affectFunction(i);
   528  					affected = true;
   529  				} else {
   530  					
   531  					var affectedProperties:Array = new Array();
   532  					var j:Number;
   533  					for (j = 0; j < p_properties.length; j++) {
   534  						if (_tweenList[i].properties[p_properties[j]] != undefined) {
   535  							affectedProperties.push(p_properties[j]);
   536  						}
   537  					}
   538  					if (affectedProperties.length > 0) {
   539  						
   540  						var objectProperties:Number = AuxFunctions.getObjectLength(_tweenList[i].properties);
   541  						if (objectProperties == affectedProperties.length) {
   542  							
   543  							p_affectFunction(i);
   544  							affected = true;
   545  						} else {
   546  							
   547  							var slicedTweenIndex:Number = splitTweens(i, affectedProperties);
   548  							p_affectFunction(slicedTweenIndex);
   549  							affected = true;
   550  						}
   551  					}
   552  				}
   553  			}
   554  		}
   555  		return affected;
   556  	}
   557  
   558  	
   565  	public static function splitTweens (p_tween:Number, p_properties:Array):Number {
   566  		
   567  		var originalTween:TweenListObj = _tweenList[p_tween];
   568  		var newTween:TweenListObj = originalTween.clone(false);
   569  
   570  		
   571  		var i:Number;
   572  		var pName:String;
   573  
   574  		
   575  		for (i = 0; i < p_properties.length; i++) {
   576  			pName = p_properties[i];
   577  			if (originalTween.properties[pName] != undefined) {
   578  				originalTween.properties[pName] = undefined;
   579  				delete originalTween.properties[pName];
   580  			}
   581  		}
   582  
   583  		
   584  		var found:Boolean;
   585  		for (pName in newTween.properties) {
   586  			found = false;
   587  			for (i = 0; i < p_properties.length; i++) {
   588  				if (p_properties[i] == pName) {
   589  					found = true;
   590  					break;
   591  				}
   592  			}
   593  			if (!found) {
   594  				newTween.properties[pName] = undefined;
   595  				delete newTween.properties[pName];
   596  			}
   597  		}
   598  
   599  		
   600  		_tweenList.push(newTween);
   601  		return (_tweenList.length - 1);
   602  		
   603  	}
   604  
   605  
   606  	
   607  	
   608  
   609  	
   614  	private static function updateTweens ():Boolean {
   615  		if (_tweenList.length == 0) return false;
   616  		var i:Number;
   617  		for (i = 0; i < _tweenList.length; i++) {
   618  			
   619  			if (!_tweenList[i].isPaused) {
   620  				if (!updateTweenByIndex(i)) removeTweenByIndex(i);
   621  				if (_tweenList[i] == null) {
   622  					removeTweenByIndex(i, true);
   623  					i--;
   624  				}
   625  			}
   626  		}
   627  
   628  		return true;
   629  	}
   630  
   631  	
   637  	public static function removeTweenByIndex (p_tween:Number, p_finalRemoval:Boolean):Boolean {
   638  		_tweenList[p_tween] = null;
   639  		if (p_finalRemoval) _tweenList.splice(p_tween, 1);
   640  		return true;
   641  	}
   642  
   643  	
   649  	public static function pauseTweenByIndex (p_tween:Number):Boolean {
   650  		var tTweening:Object = _tweenList[p_tween];	
   651  		if (tTweening == null || tTweening.isPaused) return false;
   652  		tTweening.timePaused = getCurrentTweeningTime(tTweening);
   653  		tTweening.isPaused = true;
   654  
   655  		return true;
   656  	}
   657  
   658  	
   664  	public static function resumeTweenByIndex (p_tween:Number):Boolean {
   665  		var tTweening:Object = _tweenList[p_tween];	
   666  		if (tTweening == null || !tTweening.isPaused) return false;
   667  		var cTime:Number = getCurrentTweeningTime(tTweening);
   668  		tTweening.timeStart += cTime - tTweening.timePaused;
   669  		tTweening.timeComplete += cTime - tTweening.timePaused;
   670  		tTweening.timePaused = undefined;
   671  		tTweening.isPaused = false;
   672  
   673  		return true;
   674  	}
   675  
   676  	
   682  	private static function updateTweenByIndex (i:Number):Boolean {
   683  
   684  		var tTweening:Object = _tweenList[i];	
   685  
   686  		if (tTweening == null || !tTweening.scope) return false;
   687  
   688  		var isOver:Boolean = false;		
   689  		var mustUpdate:Boolean;			
   690  
   691  		var nv:Number;					
   692  
   693  		var t:Number;					
   694  		var b:Number;					
   695  		var c:Number;					
   696  		var d:Number; 					
   697  
   698  		var pName:String;				
   699  		var eventScope:Object;			
   700  
   701  		
   702  		var tScope:Object;				
   703  		var cTime:Number = getCurrentTweeningTime(tTweening);
   704  		var tProperty:Object;			
   705  
   706  		if (cTime >= tTweening.timeStart) {
   707  			
   708  
   709  			tScope = tTweening.scope;
   710  
   711  			if (tTweening.isCaller) {
   712  				
   713  				do {
   714  					t = ((tTweening.timeComplete - tTweening.timeStart)/tTweening.count) * (tTweening.timesCalled+1);
   715  					b = tTweening.timeStart;
   716  					c = tTweening.timeComplete - tTweening.timeStart;
   717  					d = tTweening.timeComplete - tTweening.timeStart;
   718  					nv = tTweening.transition(t, b, c, d, tTweening.transitionParams);
   719  
   720  					if (cTime >= nv) {
   721  						if (tTweening.onUpdate != undefined) {
   722  							eventScope = tTweening.onUpdateScope != undefined ? tTweening.onUpdateScope : tScope;
   723  							try {
   724  								tTweening.onUpdate.apply(eventScope, tTweening.onUpdateParams);
   725  							} catch(e:Error) {
   726  								handleError(tTweening, e, "onUpdate");
   727  							}
   728  						}
   729  
   730  						tTweening.timesCalled++;
   731  						if (tTweening.timesCalled >= tTweening.count) {
   732  							isOver = true;
   733  							break;
   734  						}
   735  						if (tTweening.waitFrames) break;
   736  					}
   737  
   738  				} while (cTime >= nv);
   739  			} else {
   740  				
   741  
   742  				mustUpdate = tTweening.skipUpdates < 1 || tTweening.skipUpdates == undefined || tTweening.updatesSkipped >= tTweening.skipUpdates;
   743  
   744  				if (cTime >= tTweening.timeComplete) {
   745  					isOver = true;
   746  					mustUpdate = true;
   747  				}
   748  
   749  				if (!tTweening.hasStarted) {
   750  					
   751  					if (tTweening.onStart != undefined) {
   752  						eventScope = tTweening.onStartScope != undefined ? tTweening.onStartScope : tScope;
   753  						try {
   754  							tTweening.onStart.apply(eventScope, tTweening.onStartParams);
   755  						} catch(e:Error) {
   756  							handleError(tTweening, e, "onStart");
   757  						}
   758  					}
   759  					var pv:Number;
   760  					for (pName in tTweening.properties) {
   761  						if (tTweening.properties[pName].isSpecialProperty) {
   762  							
   763  							if (_specialPropertyList[pName].preProcess != undefined) {
   764  								tTweening.properties[pName].valueComplete = _specialPropertyList[pName].preProcess(tScope, _specialPropertyList[pName].parameters, tTweening.properties[pName].originalValueComplete, tTweening.properties[pName].extra);
   765  							}
   766  							pv = _specialPropertyList[pName].getValue(tScope, _specialPropertyList[pName].parameters, tTweening.properties[pName].extra);
   767  						} else {
   768  							
   769  							pv = tScope[pName];
   770  						}
   771  						tTweening.properties[pName].valueStart = isNaN(pv) ? tTweening.properties[pName].valueComplete : pv;
   772  					}
   773  					mustUpdate = true;
   774  					tTweening.hasStarted = true;
   775  				}
   776  
   777  				if (mustUpdate) {
   778  					for (pName in tTweening.properties) {
   779  						tProperty = tTweening.properties[pName];
   780  
   781  						if (isOver) {
   782  							
   783  							nv = tProperty.valueComplete;
   784  						} else {
   785  							if (tProperty.hasModifier) {
   786  								
   787  								t = cTime - tTweening.timeStart;
   788  								d = tTweening.timeComplete - tTweening.timeStart;
   789  								nv = tTweening.transition(t, 0, 1, d, tTweening.transitionParams);
   790  								nv = tProperty.modifierFunction(tProperty.valueStart, tProperty.valueComplete, nv, tProperty.modifierParameters);
   791  							} else {
   792  								
   793  								t = cTime - tTweening.timeStart;
   794  								b = tProperty.valueStart;
   795  								c = tProperty.valueComplete - tProperty.valueStart;
   796  								d = tTweening.timeComplete - tTweening.timeStart;
   797  								nv = tTweening.transition(t, b, c, d, tTweening.transitionParams);
   798  							}
   799  						}
   800  
   801  						if (tTweening.rounded) nv = Math.round(nv);
   802  						if (tProperty.isSpecialProperty) {
   803  							
   804  							_specialPropertyList[pName].setValue(tScope, nv, _specialPropertyList[pName].parameters, tTweening.properties[pName].extra);
   805  						} else {
   806  							
   807  							tScope[pName] = nv;
   808  						}
   809  					}
   810  
   811  					tTweening.updatesSkipped = 0;
   812  
   813  					if (tTweening.onUpdate != undefined) {
   814  						eventScope = tTweening.onUpdateScope != undefined ? tTweening.onUpdateScope : tScope;
   815  						try {
   816  							tTweening.onUpdate.apply(eventScope, tTweening.onUpdateParams);
   817  						} catch(e:Error) {
   818  							handleError(tTweening, e, "onUpdate");
   819  						}
   820  					}
   821  				} else {
   822  					tTweening.updatesSkipped++;
   823  				}
   824  			}
   825  
   826  			if (isOver && tTweening.onComplete != undefined) {
   827  				eventScope = tTweening.onCompleteScope != undefined ? tTweening.onCompleteScope : tScope;
   828  				try {
   829  					tTweening.onComplete.apply(eventScope, tTweening.onCompleteParams);
   830  				} catch(e:Error) {
   831  					handleError(tTweening, e, "onComplete");
   832  				}
   833  			}
   834  
   835  			return (!isOver);
   836  		}
   837  
   838  		
   839  		return (true);
   840  
   841  	}
   842  
   843  	
   846  	private static function init():Void {
   847  		_inited = true;
   848  
   849  		
   850  		_transitionList = new Object();
   851  		Equations.init();
   852  
   853  		
   854  		_specialPropertyList = new Object();
   855  		_specialPropertyModifierList = new Object();
   856  		_specialPropertySplitterList = new Object();
   857  	}
   858  
   859  	
   865  	public static function registerTransition(p_name:String, p_function:Function): Void {
   866  		if (!_inited) init();
   867  		_transitionList[p_name] = p_function;
   868  	}
   869  
   870  	
   877  	public static function registerSpecialProperty(p_name:String, p_getFunction:Function, p_setFunction:Function, p_parameters:Array, p_preProcessFunction:Function): Void {
   878  		if (!_inited) init();
   879  		var sp:SpecialProperty = new SpecialProperty(p_getFunction, p_setFunction, p_parameters, p_preProcessFunction);
   880  		_specialPropertyList[p_name] = sp;
   881  	}
   882  
   883  	
   890  	public static function registerSpecialPropertyModifier(p_name:String, p_modifyFunction:Function, p_getFunction:Function): Void {
   891  		if (!_inited) init();
   892  		var spm:SpecialPropertyModifier = new SpecialPropertyModifier(p_modifyFunction, p_getFunction);
   893  		_specialPropertyModifierList[p_name] = spm;
   894  	}
   895  
   896  	
   902  	public static function registerSpecialPropertySplitter(p_name:String, p_splitFunction:Function, p_parameters:Array): Void {
   903  		if (!_inited) init();
   904  		var sps:SpecialPropertySplitter = new SpecialPropertySplitter(p_splitFunction, p_parameters);
   905  		_specialPropertySplitterList[p_name] = sps;
   906  	}
   907  
   908  	
   911  	private static function startEngine():Void {
   912  		_engineExists = true;
   913  		_tweenList = new Array();
   914  
   915  		var randomDepth:Number = Math.floor(Math.random() * 999999);
   916  		var fmc:MovieClip = _root.createEmptyMovieClip(getControllerName(), 31338+randomDepth);
   917  		fmc.onEnterFrame = function(): Void {
   918  			Tweener.onEnterFrame();
   919  		};
   920  
   921  		_currentTimeFrame = 0;
   922  		updateTime();
   923  	}
   924  
   925  	
   928  	private static function stopEngine():Void {
   929  		_engineExists = false;
   930  		_tweenList = null;
   931  		_currentTime = 0;
   932  		_currentTimeFrame = 0;
   933  		delete _root[getControllerName()].onEnterFrame;
   934  		_root[getControllerName()].removeMovieClip();
   935  	}
   936  
   937  	
   940  	public static function updateTime():Void {
   941  		_currentTime = getTimer();
   942  	}
   943  
   944  	
   947  	public static function updateFrame():Void {
   948  		_currentTimeFrame++;
   949  	}
   950  
   951  	
   954  	public static function onEnterFrame():Void {
   955  		updateTime();
   956  		updateFrame();
   957  		var hasUpdated:Boolean = false;
   958  		hasUpdated = updateTweens();
   959  		if (!hasUpdated) stopEngine();	
   960  	}
   961  
   962  	
   967  	public static function setTimeScale(p_time:Number):Void {
   968  		var i:Number;
   969  		var cTime:Number;
   970  
   971  		if (isNaN(p_time)) p_time = 1;
   972  		if (p_time < 0.00001) p_time = 0.00001;
   973  		if (p_time != _timeScale) {
   974  			
   975  			for (i = 0; i<_tweenList.length; i++) {
   976  				cTime = getCurrentTweeningTime(_tweenList[i]);
   977  				_tweenList[i].timeStart = cTime - ((cTime - _tweenList[i].timeStart) * _timeScale / p_time);
   978  				_tweenList[i].timeComplete = cTime - ((cTime - _tweenList[i].timeComplete) * _timeScale / p_time);
   979  				if (_tweenList[i].timePaused != undefined) _tweenList[i].timePaused = cTime - ((cTime - _tweenList[i].timePaused) * _timeScale / p_time);
   980  			}
   981  			
   982  			_timeScale = p_time;
   983  		}
   984  	}
   985  
   986  	
   987  	
   988  
   989  	
   995  	public static function isTweening(p_scope:Object):Boolean {
   996          var i:Number;
   997  
   998          for (i = 0; i<_tweenList.length; i++) {
   999              if (_tweenList[i].scope == p_scope) {
  1000                  return true;
  1001              }
  1002          }
  1003          return false;
  1004      }
  1005  
  1006  	
  1012  	public static function getTweens(p_scope:Object):Array {
  1013          var i:Number;
  1014  		var pName:String;
  1015          var tList:Array = new Array();
  1016  
  1017          for (i = 0; i<_tweenList.length; i++) {
  1018              if (_tweenList[i].scope == p_scope) {
  1019  				for (pName in _tweenList[i].properties) tList.push(pName);
  1020              }
  1021          }
  1022  		return tList;
  1023      }
  1024  
  1025  	
  1031  	public static function getTweenCount(p_scope:Object):Number {
  1032          var i:Number;
  1033  		var c:Number = 0;
  1034  
  1035          for (i = 0; i<_tweenList.length; i++) {
  1036              if (_tweenList[i].scope == p_scope) {
  1037  				c += AuxFunctions.getObjectLength(_tweenList[i].properties);
  1038              }
  1039          }
  1040  		return c;
  1041      }
  1042  
  1043      
  1046      private static function handleError(pTweening : Object, pError : Error, pCallBackName : String) : Void{
  1047          
  1048          if (pTweening.onError != undefined && typeof(pTweening.onError == "function")){
  1049              
  1050  			var eventScope:Object = pTweening.onErrorScope != undefined ? pTweening.onErrorScope : pTweening.scope;
  1051              try {
  1052                  pTweening.onError.apply(eventScope, [pTweening.scope, pError]);
  1053              } catch (metaError : Error){
  1054  				printError(pTweening.scope.toString() + " raised an error while executing the 'onError' handler. Original error:\n " + pError +  "\nonError error: " + metaError);
  1055              }
  1056          } else {
  1057              
  1058              if (pTweening.onError == undefined){
  1059  				printError(pTweening.scope.toString() + " raised an error while executing the '" + pCallBackName.toString() + "'handler. \n" + pError );
  1060              }
  1061          }
  1062      }
  1063  
  1064  	
  1069  	public static function getCurrentTweeningTime(p_tweening:Object):Number {
  1070  		return p_tweening.useFrames ? _currentTimeFrame : _currentTime;
  1071  	}
  1072  
  1073  	
  1078  	public static function getVersion():String {
  1079  		return "AS2 1.31.69";
  1080      }
  1081  
  1082  	
  1087  	public static function getControllerName():String {
  1088  		return "__tweener_controller__"+Tweener.getVersion();
  1089      }
  1090  
  1091  
  1092  
  1093  	
  1094  	
  1095  
  1096  	
  1101  	public static function printError(p_message:String): Void {
  1102  		
  1103  		trace("## [Tweener] Error: "+p_message);
  1104  	}
  1105  
  1106  }
  1107