// MULTIMOVER
// accommodate all forms of movement desired in one external javascript
// Written my Beach Bum.  If you must copy it, please give me some credit!
// beach.bum@zzapp.org
// http://www.zzapp.org/beachbum
// banner - http://www.zzapp.org/beachbum/bbbanner.gif
// EVERYTHING IS CONTROLLED BY PARAMETERS IN CALLING SEQUENCE

/*   
USAGE
Move a layer around the screen in a variety of motions
Include this file as an external javacript at top of HTML page
Then code the image in a layer with the name 'ident'
Then add a section of javascript to call the subroutine 'mm'
Create as many image layers as you wish. 
CALLING SEQUENCE
mm('ident',xmin,xmax,ymin,ymax,interval,xpos,ypos,xvel,yvel,dvel,dacc,'options') 
	parameters define action as follows:
ident = division id; a string that must be in quotes
xmin = left edge
xmax = right edge
ymin = top edge
ymax = bottom edge
interval = time in milliseconds between recalls (lower time=faster action)
	the following parameters get reset on each call: 
xpos = x position on page
ypos = y position on page
xvel = change in x per time interval (usually 1-15)
yvel = change in y per time interval (usually 1-15)
dvel = change in direction per time interval (changed by wobble)
dacc = change in dvel per time interval (changed by wobble)
	The last is a list of control options:  loop,wrap, bounce,wobble, softedge
options = option flags; a string that must be in quotes 
	loop[=#] - continue from new edge when an edge is reached
		edge may be given as 0(T), 1(R), 2(B) 3 L)
	wrap[=#] - when an edge is reached, wrap to opposite edge
		edge may be given as 0(T), 1(R), 2(B) 3 L), 4(T&B), or 5 (L&R)
	bounce[=#] - when an edge is reached, reflect off edge
		edge may be given as 0(T), 1(R), 2(B) 3 L), 4(T&B), or 5 (L&R)
	wobble[=##] - add randomness to the movement direction 
		amplitude of wobble (1-100), where 100 is very random
	softedge[=##] - as an edge is reached, push away; 
		softness to edge (1-100), where 100 is very soft
*/

// set flags for browser type and stds conformance
ie4 = ((navigator.appName == "Microsoft Internet Explorer") && (parseInt(navigator.appVersion) >= 4 )) ;
ie5 = ((navigator.appName == "Microsoft Internet Explorer") && (navigator.appVersion.indexOf("5.") > 0 )) ;
ns4 = ((navigator.appName == "Netscape") && (parseInt(navigator.appVersion) >= 4 )) ;
agt = navigator.userAgent.toLowerCase()  ;
w3c = (agt.indexOf("gecko") != -1 ) ;
if (ie4) {
    var layerRef='document.all["';
    var styleRef='"].style';
} 
if (ns4) {
    var layerRef='document.layers["';
    var styleRef='"]';
} 
if (w3c){
    var layerRef='document.getElementById("';
    var styleRef='").style';
}
if (ie5){
    var layerRef='document.getElementById("';
    var styleRef='").style';
}

var mmtime = 0 ;
var mmRunning= 'false' ;

function mm(ident,xmin,xmax,ymin,ymax,interval,xpos,ypos,xvel,yvel,dvel,dacc,options) {
	// test for argument errors
	errorflag=mm.arguments.length-13;
	if (errorflag != 0){
		if (errorflag>0) {usagealert('3') }
		if (errorflag<0) {usagealert('4') }
	}
	// Begin processing
	if ((ie5|ie4|ns4|w3c) && (errorflag == 0)) {
	loop = 0 ;
	wrap = 0 ;
	bounce = 0 ;
	wobble = 0 ;
	softedge = 0 ;
	variance = 50 ;
	hardness = 50 ;
	l_edge = -1 ;
	w_edge = -1 ;
	b_edge = -1 ;

	if (options != "" ) {
			// confirm valid option list
			if (isFinite(options)){usagealert('5')}
	// parse options
	options=options.toLowerCase();
	loop = (options.indexOf("loop") != -1 );
	if (loop){
		loopvstart = options.indexOf("loop") +5;
		loopstring = options.substr(loopvstart);
		if(isNaN(parseInt(loopstring))) {
			// loop from all edges if not given ;
			} else {
			l_edge = parseInt(loopstring);
			if(l_edge<0) {l_edge=0; usagealert('9')}  ;
			if(l_edge>3) {l_edge=0; usagealert('9')}  ;
			}
		}
	wrap = (options.indexOf("wrap") != -1 );
	if (wrap){
		wrapvstart = options.indexOf("wrap") +5;
		wrapstring = options.substr(wrapvstart);
		if(isNaN(parseInt(wrapstring))) {
			// wrap from all edges if not given ;
			} else {
			w_edge = parseInt(wrapstring);
			if(w_edge<0) {w_edge=4; usagealert('8')}  ;
			if(w_edge>5) {w_edge=4; usagealert('8')}  ;
			}
		}
	bounce = (options.indexOf("bounce") != -1 );
	if (bounce){
		bouncevstart = options.indexOf("bounce") +7;
		bouncestring = options.substr(bouncevstart);
		if(isNaN(parseInt(bouncestring))) {
			// bounce from all edges if not given
			} else {
			b_edge = parseInt(bouncestring);
			if(b_edge<0) {b_edge=2; usagealert('7')}  ;
			if(b_edge>5) {b_edge=2; usagealert('7')}  ;
			}
		}
	wobble = (options.indexOf("wobble") != -1 );
	// find option values if given
	if (wobble){
		wobblevstart = options.indexOf("wobble") +7;
		wobblestring = options.substr(wobblevstart);
		if(isNaN(parseInt(wobblestring))) {
			// Use default
			} else {
			variance = parseInt(wobblestring);
			if(variance<=0) {variance=1; usagealert('2')}  
			if(variance>100) {variance=100; usagealert('2')}  
			}
		}
	softedge = (options.indexOf("softedge") != -1 );
	if (softedge){
		softvstart = options.indexOf("softedge") +9;
		softstring = options.substr(softvstart);
		if(isNaN(parseInt(softstring))) {
			// Use default
			} else {
			hardness = parseInt(softstring);
			if(hardness<=0) {hardness=1; usagealert('1')}  ;
			if(hardness>100) {hardness=100; usagealert('1')}  ;
			}
		}
	}

 	if(wobble|softedge) {
		// common code
		velocity = Math.sqrt((xvel*xvel)+(yvel*yvel)) ;
		}
 	if(wobble) {
		// add variation to the direction VALIDATED
		vw = variance/100; 
		dacc =  vw*Math.PI*(.5 - Math.random() ) ;
		dvel =  dvel + dacc ;
		if(dvel < -vw) { dvel = -vw }  
		if(dvel > vw ) { dvel = vw }  
		}
     if(softedge) {
		// repell from the edges VALIDATED
		ss = .006 * (hardness + .5*Math.abs(velocity)) ;
		buffer = 15 + .5*(100 - hardness) + Math.abs(velocity)  ;
		if ((xmax-xpos)<buffer) { 
			xvel = xvel-ss*(buffer-(xmax-xpos)) ;
//			if (Math.abs(yvel) <= .01) { yvel = (.5-Math.random()) }
			} 
		if ((ymax-ypos)<buffer) { 
			yvel = yvel-ss*(buffer-(ymax-ypos)) ;
//			if (Math.abs(xvel) <= .01) { xvel = (.5-Math.random()) }
			} 
		if ((xpos-xmin)<buffer) { 
			xvel = xvel-ss*((xpos-xmin)-buffer) ;
//			if (Math.abs(yvel) <= .01) { yvel = (.5-Math.random()) }
			} 
		if ((ypos-ymin)<buffer) { 
			yvel = yvel-ss*((ypos-ymin)-buffer) ;
//			if (Math.abs(xvel) <= .01) { xvel = (.5-Math.random()) }
			} 	
		}
 	if(wobble|softedge) {
		direction = Math.atan2(yvel,xvel);
		newdirection = direction + dvel ;
		if (newdirection > Math.PI){ newdirection = newdirection - 2*Math.PI }
		if (newdirection < -Math.PI){ newdirection = newdirection + 2*Math.PI }
		xvel = Math.cos(newdirection) * velocity ;
		yvel = Math.sin(newdirection) * velocity ;
		}

     // advance position
     xpos = xpos+xvel;
     ypos = ypos+yvel;

	edgeflag="" ;
	// determine if an edge has been reached
		if ((xpos>xmax)&&(xvel>=0)){edgeflag="right"}
		if ((xpos<xmin)&&(xvel<=0)){edgeflag="left"}
		if ((ypos>ymax)&&(yvel>=0)){edgeflag="bottom"}
		if ((ypos<ymin)&&(yvel<=0)){edgeflag="top"}
	// end of edge testing

	var edge_act = 1 ;
	if (edgeflag != "" ){
		// an edge was reached 
		if ((bounce)&&(edge_act)){
				// reverse direction off edge OPTIMIZED
				switch (edgeflag){
					case "top" :
					if ((b_edge == 0)|(b_edge == 4)|(b_edge == -1)){
						yvel = -yvel;
						edge_act = 0;
					}
					break ;
					case "right" :
					if ((b_edge == 1)|(b_edge == 5)|(b_edge == -1)){
						xvel = -xvel;
						edge_act = 0;
					}
					break ;
					case "bottom" :
					if ((b_edge == 2)|(b_edge == 4)|(b_edge == -1)){
						yvel = -yvel;
						edge_act = 0;
					}
					break ;
					case "left" :
					if ((b_edge == 3)|(b_edge == 5)|(b_edge == -1)){
						xvel = -xvel;
						edge_act = 0;
					}
					break ;
				}
			}
			if ((wrap)&&(edge_act)){
				// reset position to opposite edge OPTIMIZED
				switch (edgeflag){
					case "top" :
					if ((w_edge == 0)|(w_edge == 4)|(w_edge == -1)){
						ypos = ymax;
						edge_act = 0;
					}
					break ;
					case "right" :
					if ((w_edge == 1)|(w_edge == 5)|(w_edge == -1)){
						xpos = xmin;
						edge_act = 0;
					}
					break ;
					case "bottom" :
					if ((w_edge == 2)|(w_edge == 4)|(w_edge == -1)){
						ypos = ymin;
						edge_act = 0;
					}
					break ;
					case "left" :
					if ((w_edge == 3)|(w_edge == 5)|(w_edge == -1)){
						xpos = xmax;
						edge_act = 0;
					}
					break ;
				}
			}
		if ((loop)&&(edge_act)){
			// loop - start from new edge and new direction VALIDATED
			velocity = Math.sqrt((xvel*xvel)+(yvel*yvel)) ;
			if (l_edge  ==  -1){
				side = rand(3) ;
				newdirection = Math.random() * Math.PI ;
				} else {
				side = l_edge;
				newdirection = Math.atan2(yvel,xvel);
				if (newdirection > Math.PI){ newdirection = newdirection - 2*Math.PI }
				if (newdirection < -Math.PI){ newdirection = newdirection + 2*Math.PI }
				}
			width = xmax-xmin ;
			height = ymax-ymin ;
		switch (side) {
					case "0" :
					// start off top edge
					xpos = xmin + rand(width) ;
					ypos = ymin ;
					xvel = Math.cos(newdirection) * velocity ;
					yvel = Math.abs(Math.sin(newdirection)) * velocity ;
					break ;
					case "1" :
					// start off right edge
					xpos = xmax ;
					ypos = ymin+ rand(height) ;
					xvel = -Math.abs(Math.cos(newdirection)) * velocity ;
					yvel = Math.sin(newdirection) * velocity ;
					break ;
					case "2" :
					// start off bottom edge
					xpos = xmin + rand(width) ;
					ypos = ymax ;
					xvel = Math.cos(newdirection) * velocity ;
					yvel = -Math.abs(Math.sin(newdirection)) * velocity ;
					break ;
					case "3" :
					// start off left edge
					xpos = xmin ;
					ypos = ymin+ rand(height) ;
					xvel = Math.abs(Math.cos(newdirection)) * velocity ;
					yvel = Math.sin(newdirection) * velocity ;
					break ;
				}
			}
		}
		// end of edge processing

	if ((edgeflag == "")|loop|wrap|bounce){		
		// move layer and recall subroutine 
    		eval(layerRef + ident + styleRef + '.top = ypos');
    		eval(layerRef + ident + styleRef + '.left = xpos');
    		mmtime=setTimeout("mm('"+ident+"',"+xmin+","+xmax+","+ymin+","+ymax+","+interval+","+xpos+","+ypos+","+xvel+","+yvel+","+dvel+","+dacc+",'"+options+"')",interval) ;
		mmRunning= 'true' ;
		}
		// end of move and recall
	}
	// end of action for acceptable browsers
}
// end of function mm
	
function usagealert(x){
// flag errors in command line
if(x == 1){alert('WARNING: Valid softedge range is 1-100')}
if(x == 2){alert('WARNING: Valid wobble range is 1-100')}
if(x == 3){alert('WARNING: Too many parameters:\nUSAGE: mm(identstring,xmin,xmax,ymin,ymax,interval,xpos,ypos,xvel,yvel,dvel,dacc,optionstring)\nOPTIONS: loop, wrap, bounce, wobble[=##], softedge[=##] ')}
if(x == 4){alert('Too few parameters:\nUSAGE: mm(identstring,xmin,xmax,ymin,ymax,interval,xpos,ypos,xvel,yvel,dvel,dacc,optionstring)\nOPTIONS: loop, wrap, bounce, wobble[=##], softedge[=##] ')}
if(x == 5){alert('Options must be a string or string variable')}
if(x == 6){alert('Ident must be a string or string variable')}
if(x == 7){alert('WARNING: If given, valid bounce edge may be 0 (T), 1 (R), 2 (B), 3 (L), 4 (T&B), or 5 (L&R)')}
if(x == 8){alert('WARNING: If given, wrap edge may be 0 (T), 1 (R), 2 (B) 3 (L), 4 (T&B), or 5 (L&R)')}
if(x == 9){alert('WARNING: If given, loop (starting) edge may be 0 (T), 1 (R), 2 (B) or 3 (L)')}
}

// This is the random integer number generator: 
// usage: var x = rand(range) ;
function rand(range) {
seed = Math.round(Math.random() * range);
return(seed) ;
  }

