DAN ZEN EXPO - CODE EXHIBIT - TILTY
package {
	
	import com.danzen.frameworks.Easy;
	import com.danzen.frameworks.ZenPage;
	import com.danzen.utilities.DynamicObject;
	import com.danzen.utilities.ProportionDamp;
	import com.greensock.TweenLite;
	import com.greensock.easing.Back;
	import com.greensock.easing.Elastic;
	
	import flash.desktop.NativeApplication;
	import flash.desktop.SystemIdleMode;
	import flash.display.MovieClip;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.AccelerometerEvent;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	import flash.sensors.Accelerometer;
	import flash.ui.Keyboard;
	import flash.utils.Timer;
	
	
	public class Tilty2 extends MovieClip {
		
		private var assets:Assets;
		//private var platform:String = "apple";
		//private var platform:String = "blackberry";
		private var platform:String = "android";
		
		
		// ZenPage vars 
		// page name is the MovieClip instance name in the assets you pass in to ZenPage
		// backing is the name of the backing MovieClip in assets for the page (optiona)
		// button name is a MovieClip instance name of a button in your page MovieClip
		// go is the instance name of one of the pages (optional)
		// command will trigger a ZenPage.COMMAND event (optional)
		// command and param (optional) properties will then be available on ZenPage
		
		private var zp:ZenPage;		
		private var pagesXML:XML = <pages>
			<page name="intro" backing="backing1">
				<button name="continueBut" go="rules" />			
			</page>
			<page name="rules" backing="backing2">
				<button name="prevBut" go="intro" />
				<button name="playBut" go="game" />
				<button name="helpBut" go="help" />
				<button name="aboutBut" go="about" />
			</page>
			<page name="help" backing="backing3">
				<button name="prevBut" go="rules" />
				<button name="videoBut" command="doURL" param="http://www.tilty.mobi/tilty/video.html" />
			</page>
			<page name="about" backing="backing3">
				<button name="prevBut" go="rules" />
				<button name="danzen" command="doURL" param="http://danzen.com" />
				<button name="danzenBut" command="doURL" param="http://danzen.com" />
			</page>
			<page name="game" backing="backing4">
				<button name="prevBut" go="rules" />
				<button name="togetherBut" go="target" command="doPlay" />
				<button name="scoreBut" go="score" command="goScore" />
				<button name="totalsBut" go="totals" command="goTotals" />
			</page>
			<page name="target" backing="backing5">				
			</page>
			<page name="score" backing="backing6">
				<button name="prevBut" go="game" />
				<button name="winBut" command="doScore" param="win" />
				<button name="tieBut" command="doScore" param="tie" />
				<button name="lossBut" command="doScore" param="loss" />
				<button name="rateBut" command="doAppStore" />
			</page>
			<page name="totals" backing="backing6">
				<button name="prevBut" go="game" />
				<button name="clearBut" command="doClear" />
			</page>			
		</pages>			
		private var pages:Object; // used with ZenPages.getPages() method to access pages in ZenPages
		
		//private var mySO:SharedObject;
		private var clockTimer:Timer;		
		private var clockStartTime:Number = 20;
		private var beepTimer:Timer;
		private var beepInterval:Number = 5000;
		private var myScore:Number = -1;
		private var tiltCount:Number;
		private var cX:Number;
		private var cY:Number;
		private var cYAdjust:Number = 1.12;
		private var scoreCheck:Boolean = false;
		private var lastScoreType:String;
		private var sW:Number;
		private var sH:Number;
		private var sWDesign:Number = 320;
		private var sHDesign:Number = 480;
		
		private var myData:MyData;
		
		[Embed (source="newTee.mp3" )]
		private var TeeTee:Class;
		private var mySound:Sound;
		
		[Embed (source="bleep.mp3" )]
		private var Bleep:Class;
		private var myBleep:Sound;
		
		[Embed (source="beep.mp3" )]
		private var Beep:Class;
		private var myBeep:Sound;
		
		[Embed (source="rollGood.mp3" )]
		private var Roll:Class;
		private var myRoll:Sound;
		private var myRollChannel:SoundChannel;
		
		private var accel:Accelerometer;
		private var pdX:ProportionDamp;
		private var pdY:ProportionDamp;
		
		public function Tilty2()	{		
			
			trace ("hi from Tilty");
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			stage.autoOrients = false;			
			addEventListener(Event.ADDED_TO_STAGE, init);			
		}
		
		private function init(e:Event):void {		
			
			if (platform != "blackberry") {
				NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, handleActivate);			
				NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, handleDeactivate);			
				NativeApplication.nativeApplication.addEventListener(KeyboardEvent.KEY_DOWN, handleKeys);
			} 
			
			mySound = new TeeTee() as Sound;
			myBeep = new Beep() as Sound;
			myBleep = new Bleep() as Sound;
			myRoll = new Roll() as Sound;
			
			// set up stage and bring in assets
			if (stage.fullScreenWidth > 0) {
				sW = stage.fullScreenWidth;
				sH = stage.fullScreenHeight;
			} else {
				sW = stage.stageWidth;
				sH = stage.stageHeight;
			}			
			stage.color = 0x000000;			
			assets = new Assets();
			
			// two size backgrounds are provided default and large
			if (sW >= 640) {				
				var page:XML;				
				if (sW == sH) {
					for each (page in pagesXML.page) {
						page.@backing += "Square";	
					}	
				} else if (sH >= 1136) {
					for each (page in pagesXML.page) {
						page.@backing += "Tall";
					}	 				
				} else {					
					for each (page in pagesXML.page) {
						page.@backing += "Large";	
					}
				}
			}	
			
			
			
			// create the page navigation
			zp = new ZenPage(assets, pagesXML);			
			zp.addEventListener(ZenPage.COMMAND, doCommand);
			addChild(zp);	
			
			// scale the pages and backings
			var clip:MovieClip;
			for (var i:uint=0; i maxWidth) {				
				clip.scaleX = clip.scaleY = 1;
				clipScale = maxWidth / originalWidth;
				clip.scaleX = clip.scaleY = clipScale;	
				clip.x = minX;
				clip.y = (sH - originalHeight*clipScale) / 2;
			} else {		
				clip.x = (sW - originalWidth*clipScale) / 2;
				clip.y = minY;
			}	
		}		
		
		private function doCommand(e:Event):void {
			switch (zp.command) {
				case "goScore":
					goScore();
					break;
				case "doScore":
					if (myScore < 0) {return;}
					addChild(assets.scorePop);
					var messages:Object = {win:1, tie:2, loss:3};
					assets.scorePop.pop.message.gotoAndStop(messages[zp.param]);
					if (scoreCheck) {
						for (var t:String in messages) {
							pages.score.buttonSet[t+"Back"].gotoAndStop(1);
						}
						pages.score.buttonSet[zp.param+"Back"].gotoAndStop(2);
						var d:Object = DynamicObject.copy(myData.scores);	
						
						if (lastScoreType == "win") {
							d.wins = myData.scores.wins - 1;
						} else if (lastScoreType == "tie") {
							d.ties = myData.scores.ties - 1;
						} else if (lastScoreType == "loss") {
							d.losses = myData.scores.losses - 1;
						} else if (lastScoreType == "nil") {
							d.nils = myData.scores.nils - 1;
						}
						lastScoreType = zp.param;
						if (zp.param == "win") {
							d.wins = myData.scores.wins + 1;										
						} else if(zp.param == "tie") {
							d.ties = myData.scores.ties + 1;
						} else if (zp.param == "loss") {
							d.losses = myData.scores.losses + 1;
						}
						myData.scores = d;
					}
					break;
				case "doClear":
					addChild(assets.clearPop);	
					break;
				case "doURL":
					navigateToURL(new URLRequest(zp.param));
					break;
				case "doAppStore":
					trace ("app store");
					if (platform == "apple") {
						navigateToURL(new URLRequest("https://itunes.apple.com/app/tilty/id572308446"));
					} else if (platform == "blackberry") {
						navigateToURL(new URLRequest("http://appworld.blackberry.com/webstore/content/27344629"));
					} else if (platform == "android") {
						navigateToURL(new URLRequest("https://market.android.com/details?id=air.com.danzen.tilty"));
					}					
					break;		
				case "doPlay":
					trace ("play");
					tiltCount = 0;
					pages.target.scoreText.text = "100";
					pages.target.ball.x = sWDesign/2;
					pages.target.ball.y = sHDesign/2;
					myScore = 100;
					scoreCheck = false;
					lastScoreType = "";
					pages.target.clockText.text = "0:"+clockStartTime;
					clockTimer.reset();
					clockTimer.start();				
					
					//myBeep.play();
					//myBleep.play();
					myRollChannel = myRoll.play();
					beepTimer.reset();
					beepTimer.start();		
					
					var ballRadius:Number = 30; // hard coded because of drop shadow
					//pdX = new ProportionDamp(ballRadius,sWDesign-ballRadius,.1,0,sW);
					//pdY = new ProportionDamp(ballRadius,sHDesign-ballRadius,.1,0,sH);
					
					/*if (zp.param == "1") {
					pdX = new ProportionDamp(ballRadius,sWDesign-ballRadius,.1,-.1,.1);
					pdY = new ProportionDamp(ballRadius,sHDesign-ballRadius,.1,-.1,.1);
					} else if (zp.param == "2") {
					*/
					pdX = new ProportionDamp(ballRadius,sWDesign-ballRadius,.1,-.2,.2);
					pdY = new ProportionDamp(ballRadius,sHDesign-ballRadius,.1,-.2,.2);
					/*
					} else if (zp.param == "3") {
					pdX = new ProportionDamp(ballRadius,sWDesign-ballRadius,.1,-.3,.3);
					pdY = new ProportionDamp(ballRadius,sHDesign-ballRadius,.1,-.3,.3);
					}*/
					
					pdX.immediate(0);
					pdY.immediate(0);
					if (Accelerometer.isSupported) {
						accel.addEventListener(AccelerometerEvent.UPDATE, accelUpdate);	
						addEventListener(Event.ENTER_FRAME, animate);
					} 																
					break;	
				case "goTotals":
					
					var myDataNames:Array = ["wins", "ties", "losses", "nils", "games", "total"];
					for (var i:uint=0; i 0) {
						pages.totals.averageText.text = String(Math.round(myData.scores.total / myData.scores.games));
					} else {
						pages.totals.averageText.text = "-";
					}
					
			}
		}
		
		private var targetX:Number=0;
		private var targetY:Number=0;
		
		private function accelUpdate(e:AccelerometerEvent):void {
			targetX = e.accelerationX;
			targetY = e.accelerationY;
		}
		
		private function animate(e:Event):void {
			pages.target.ball.x = pdX.convert(-targetX);
			pages.target.ball.y =  pdY.convert(targetY);
			
			//pages.target.ball.x = pdX.convert(mouseX);
			//pages.target.ball.y =  pdY.convert(mouseY);
		}
		
		
		
		private function doClock(e:TimerEvent):void {
			var t:Number = Math.ceil((clockStartTime*1000 - clockTimer.currentCount*100)/1000);
			var t2:String = (t<10)? "0"+t : String(t);
			pages.target.clockText.text = "0:" + t2;
			if (t <= 0) {				
				clockTimer.stop();
				beepTimer.stop();
				myRollChannel.stop();
				mySound.play();				
				lastScoreType = "nil";
				zp.go(pages.score);
				goScore();				
				var d:Object = DynamicObject.copy(myData.scores);
				d.games = myData.scores.games + 1;
				d.nils = myData.scores.nils + 1;	
				d.total = myData.scores.total + myScore;
				myData.scores = d;
				scoreCheck = true;		
				pages.score.scoreText.text = String(myScore);
				if (Accelerometer.isSupported) {
					accel.removeEventListener(AccelerometerEvent.UPDATE, accelUpdate);	
					removeEventListener(Event.ENTER_FRAME, animate);
				} 	
				pdX.dispose(); pdX = null;
				pdY.dispose(); pdY = null;
			}
			
			// if ball is in center do not reduce score
			// if ball is in second ring reduce by half score
			// if ball is outside ring reduce by full score
			
			var targetResult:Number = checkTarget(pages.target.ball.x, pages.target.ball.y);
			tiltCount += targetResult;	
			
			myScore = Math.round(100-tiltCount*100/1000/clockStartTime*100);
			pages.target.scoreText.text = String(myScore);
			
		}
		
		private function doBeep(e:TimerEvent):void {
			myBeep.play();
			myBleep.play();
		}
		
		private function goScore():void {
			if (myScore < 0) {
				pages.score.scoreText.text = "-";				
			} else {
				pages.score.scoreText.text = String(myScore);
			}
			if (lastScoreType == "nil") {
				var types:Array = ["win", "tie", "loss"];
				for (var i:uint=0; i 0) {
				pages.totals.averageText.text = String(Math.round(myData.scores.total / myData.scores.games));
			} else {
				pages.totals.averageText.text = "-";
			}
		}
		
		private function handleActivate(event:Event):void { 
			NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;  
		}            
		
		private function handleDeactivate(event:Event):void    {
			NativeApplication.nativeApplication.exit(); 			
		}            
		
		private function handleKeys(event:KeyboardEvent):void { 
			if(event.keyCode == Keyboard.BACK) {
				NativeApplication.nativeApplication.exit();
			}		
		}       
		
	}
}

package com.danzen.frameworks {
	
	/*	
	ZenPage - by Inventor Dan Zen - http://danzen.com - free to use and change
	Used in Touchy and Tilty mobile apps: http://touchy.mobi http://tilty.mobi	
	Sample file http://danzen.com/zenpage/zenpage.zip
	More AS Classes at http://flashfeathers.com http://easyactionscript.wordpress.com
	
	ZenPage is a light framework class to handle pages, buttons and navigation
	
	ASSETS
	Stack pages in a single MovieClip with instance names for each page.
	Optionally, also stack background clips with instance names (helps to reuse backrounds)
	Separating backgrounds allows for different background graphics for multiple screen sizes
	and different scaling and positioning for content and backgrounds (common in mobile).
	All your buttons should be in the pages clips with instance names along with the content.
	
	CODE
	See the ZenPageExample file for how to use ZenPage.
	In general, how it works is you pass ZenPage the assets 
	From then on you access the pages through ZenPage if you have to	
	You also pass ZenPage XML that identifies your pages and buttons
	and sets which page a button goes to or what command to call if it is a function.
	If you have no commands, your navigation is complete - you don't have to do a thing.
	If you do have commands, you have to specify actions for the commands like navigateToURL	
	
	*/
	
	import flash.display.MovieClip;
	import flash.events.*;
	
	public class ZenPage extends MovieClip	{
		
		private var assets:MovieClip;
		private var pagesXML:XML;		
		private var pages:Object = {};
				
		public static const COMMAND:String = "command"; // event for command call
		public var command:String; // command event puts command string here
		public var param:String; // command puts param value here
		
		public function ZenPage(theAssets:MovieClip, thePagesXML:XML) {	
			
			trace ("hi from ZenPage");
			
			assets = theAssets;
			pagesXML = thePagesXML;				
			preparePages();			
		}
		
		private function preparePages():void {
					
			var page:XML;
			var p:MovieClip;
			var button:XML;
			var b:MovieClip;
			
			for each (page in pagesXML.page) {
				pages[page.@name] = MovieClip(assets[page.@name]);	
			}
						
			for each (page in pagesXML.page) {
				p = MovieClip(pages[page.@name]);	
				if (page.@backing) {
					p.backing = MovieClip(assets[page.@backing]);
				} 
				for each (button in page.button) {
					b = MovieClip(p[button.@name]);
					b.buttonMode = true;	
					// add info to button clip
					b.go = ("@go" in button) ? button.@go : null;
					b.command =  ("@command" in button) ? button.@command: null;
					b.param = ("@param" in button) ? button.@param : null;
					b.addEventListener(MouseEvent.CLICK, goPage);
				}
			}			
		}
		
		private function goPage(e:MouseEvent):void {			
			var b:MovieClip = MovieClip(e.currentTarget);	// button		
			if (b.go) {
				go(pages[b.go]);
			} 
			if (b.command) {
				command = b.command
				param = b.param;
				dispatchEvent(new Event(ZenPage.COMMAND));
			} 
		}
		
		public function go(p:MovieClip):void {			
			while (numChildren > 0) {
				removeChildAt(0);				
			}	
			if (p.backing) {
				addChild(p.backing);
			}
			addChild(p);			
		}
		
		public function getPages():Object {
			return pages;
		}
		
	}
}


package com.danzen.utilities {
	
	import flash.utils.ByteArray;
	
	public class DynamicObject {
		
		
		public static function compare(a:Object, b:Object):Boolean {
			var myBA:ByteArray = new ByteArray();
			myBA.writeObject(a);
			var myBA2:ByteArray = new ByteArray();
			myBA2.writeObject(b);			
			
			var size:uint = myBA.length;
			if (myBA.length == myBA2.length) {
				myBA.position = 0;
				myBA2.position = 0; 								
				var count:Number = 0;
				while (myBA.position < size) {
					count++
					if (myBA.readByte() != myBA2.readByte()) {						
						return false;
					}
				}    
				return true;                        
			}
			return false;
		}
		
		public static function difference(a:Object,b:Object):Number {
			var diff:Number = 0;
			for (var i:Object in a) {
				diff += Math.abs(Number(a[i] - b[i]));
			}
			return diff;					
		}		
		
		public static function copy(source:Object):* {
			var myBA:ByteArray = new ByteArray();
			myBA.writeObject(source);
			myBA.position = 0;
			return(myBA.readObject());
		}		
	}
}

package com.danzen.utilities {
		
	// ProportionDamp Class - Dan Zen http://www.danzen.com http://flashfeathers.com
	// adjusts an input value to an output value on a different scale with damping
	
	// put in min and max for the output scale (say volume)
	// put in desired damping with 1 being no damping and .01 being the default
	// put in min and max for the input scale (say x values, 0 and 1 are the defaults)	
		
	// in your own enter frame event function or whatever call convert()
	// pass in your input property (say the mouseX)
	// convert will return the output property with easing (for instance, a volume)	
	
	// the object always starts by assuming baseMin as baseValue.
	// if you want to start or go to an immediate value without easing then
	// call the immediate() method with your desired baseValue (not targetValue)
		
	import flash.display.Sprite;
	import flash.events.Event;

	public class ProportionDamp extends Sprite {

		// constructor parameters
		private var myTargetMin:Number;
		private var myTargetMax:Number;	
		private var myBaseMin:Number;
		private var myBaseMax:Number;						
		private var myDamp:Number; // damping can be changed via damp get/set method property	
		private var myFactor:Number; // set to 1 for increasing and -1 for decreasing
		private var myRound:Boolean; // true to round results to whole number (good if property is frameNumber)
		
		// proportion
		private var baseAmount:Number;
		private var proportion:Number;
		private var targetDifference:Number;	
		private var targetAmount:Number;	
		
		// damping			
		private var differenceAmount:Number;
		private var desiredAmount:Number=0;
		public var lastAmount:Number = 0;

		public function ProportionDamp (
					theTargetMin:Number,
					theTargetMax:Number,		
					theDamp:Number=.01,	
					theBaseMin:Number=0,
					theBaseMax:Number=1,					
					theFactor:Number=1,
					theRound:Boolean=false) {
			
			
			myTargetMin = theTargetMin;
			myTargetMax = theTargetMax;						
			myBaseMin = theBaseMin;
			myBaseMax = theBaseMax;
			myDamp = theDamp;
			myFactor = theFactor;
			myRound = theRound;
			
			baseAmount = myBaseMin; // just start at the min otherwise call immediate(baseValue);
			lastAmount = myTargetMin;					
			
			addEventListener(Event.ENTER_FRAME, calculate);
			
		}
				
		private function calculate(e:Event):void {				
			
			if (isNaN(baseAmount)) {return;}
							
			baseAmount = Math.max(baseAmount, myBaseMin);
			baseAmount = Math.min(baseAmount, myBaseMax);
			proportion = (baseAmount - myBaseMin) / (myBaseMax - myBaseMin);
			targetDifference = myTargetMax - myTargetMin;			
			targetAmount = myTargetMin + myFactor * targetDifference * proportion;
			
			desiredAmount = targetAmount;			
			differenceAmount = desiredAmount - lastAmount;									
			lastAmount += differenceAmount*myDamp;						
			if (myRound) {lastAmount = Math.round(lastAmount);}			
			
		}		
		
		public function immediate(n:Number):void {
			convert(n);
			calculate(null);
			lastAmount = targetAmount;
			if (myRound) {lastAmount = Math.round(lastAmount);}	
		}
		
		public function convert(n:Number):Number {
			baseAmount = n;
			return lastAmount;
		}
		
		public function set damp(n:Number):void {
			myDamp = n;
		}
		public function get damp():Number {
			return myDamp;
		}
		
		public function dispose():void {
			removeEventListener(Event.ENTER_FRAME, calculate);
		}
	}	
}