In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Wonderfl Tower Defense (Mockup Test)

-----------------------------------------------------
* まだ全然出来てないんですが、とりあえずテストで投稿。
* 今後更新を重ねてちゃんと完成まで持っていく予定です。
* 
* 4月から本気出す
* 
* -----------------------------------------------------
Get Adobe Flash player
by o8que 24 Mar 2010
/**
 * Copyright o8que ( http://wonderfl.net/user/o8que )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/q7nD
 */

/* -----------------------------------------------------
 * まだ全然出来てないんですが、とりあえずテストで投稿。
 * 今後更新を重ねてちゃんと完成まで持っていく予定です。
 * 
 * 4月から本気出す
 * 
 * -----------------------------------------------------
 */

package {
	import com.bit101.components.ProgressBar;
	import flash.display.*;
	import flash.events.Event;
	
	public class Main extends Sprite {
		public static var nodes:Array;
		public static var towers:Array;
		public static var enemies:Array;
		public static var bullets:Array;
		public static var goals:Array;
		
		private var _fieldMap:FieldMap;
		private var _frontend:Frontend;
		
		public function Main() {
			var preloader:Preloader = ImageFactory.preload(this);
			preloader.addEventListener(Event.COMPLETE, initialize);
		}
		
		private function initialize(e:Event):void {
			e.target.removeEventListener(Event.COMPLETE, initialize);
			
			graphics.beginFill(0x000000);
			graphics.drawRect(0, 0, 465, 465);
			graphics.endFill();
			
			initializeNodes();
			towers = [];
			enemies = [];
			bullets = [];
			goals = Parameter.getGoals();
			
			addChild(_fieldMap = new FieldMap( -9, 12));
			addChild(_frontend = new Frontend());
		}
		
		private function initializeNodes():void {
			nodes = [];
			for (var row:int = 0; row < Parameter.NODE_ROWS; row++) {
				nodes[row] = [];
				for (var col:int = 0; col < Parameter.NODE_COLS; col++) {
					nodes[row][col] = new Node(col, row, Parameter.MAP_DATA[row][col]);
				}
			}
		}
	}
}

//package {
	import flash.geom.Point;
	
	//public 
	class Parameter {
		public static const FRAMERATE:int = 30;						// fps
		public static const NODE_SIZE:Number = 16;					// ノードの大きさ
		public static const NODE_COLS:int = 24;						// ノードの行数(横に並ぶ数)
		public static const NODE_ROWS:int = 26;						// ノードの列数(縦に並ぶ数)
		public static const TOWER_SIZE:Number = NODE_SIZE * 2;		// タワーの大きさ
		public static const TOWER_IMAGE_SIZE:int = TOWER_SIZE + 8;	// タワーの画像の大きさ
		public static const TOWER_SELL_RATE:Number = 0.8;			// タワー売却値の率
		public static const SLOWING_TIME:Number = 4.0;				// スロー状態の持続時間
		public static const INITIAL_LIVES:int = 20;					// ライフの初期値
		public static const INITIAL_GOLD:int = 10000;					// ゴールドの初期値
		
		// マップを構成する各ノードの属性の情報
		public static const MAP_DATA:Array = [
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
			[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
			[1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1],
			[1,0,0,0,0,0,0,0,0,0,2,1,1,2,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
			[1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1],
			[1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1]
		];
		
		// 読み込むべき外部画像のリスト
		public static const EXTERNAL_IMAGES:Object = {
			Fieldmap : "http://assets.wonderfl.net/images/related_images/5/5f/5ff7/5ff7c989b7a1068c50a7008713931f651804468c",
			Arrow : "http://assets.wonderfl.net/images/related_images/6/63/6343/63436a18a4aea50e9219db1a18fed0c3feddfd45",
			Gatling : "http://assets.wonderfl.net/images/related_images/4/40/4008/4008e51eb77440a7421dfc0363f55fc4784f069c",
			Bomb : "http://assets.wonderfl.net/images/related_images/b/b5/b5d2/b5d2a5c08373d1bd07375d9ad74bf502f9fcccc8",
			Misslie : "http://assets.wonderfl.net/images/related_images/6/69/6950/6950fb7ed305b34a23392d7b1371a13b49a7ccbc",
			Frost : "http://assets.wonderfl.net/images/related_images/6/69/6931/6931d44cd4bbf0feb60b4c2d24ffa6f29098479b",
			Vortex : "http://assets.wonderfl.net/images/related_images/d/df/df45/df45671017d8385c582396d44f98e8e2fd705ee2",
			Laser : "http://assets.wonderfl.net/images/related_images/9/92/9245/9245550bd2d49a69cec242205454199d1e4f6b87"
		};
		
		private static const data:XML =
		<root>
			<towers>
				<tower name="Arrow" ground="1" air="1" slow="0" splash="0">
					<stats rank="E" cost="10"   damage="30"   range="60"  firerate="1.5" />
					<stats rank="D" cost="20"   damage="60"   range="65"  firerate="1.5" />
					<stats rank="C" cost="40"   damage="90"   range="70"  firerate="1.5" />
					<stats rank="B" cost="80"   damage="120"  range="75"  firerate="1.5" />
					<stats rank="A" cost="280"  damage="150"  range="150" firerate="1.5" />
				</tower>
				<tower name="Gatling" ground="1" air="1" slow="0" splash="0">
					<stats rank="E" cost="20"   damage="15"   range="50"  firerate="3" />
					<stats rank="D" cost="40"   damage="30"   range="55"  firerate="4" />
					<stats rank="C" cost="80"   damage="45"   range="60"  firerate="5" />
					<stats rank="B" cost="160"  damage="60"   range="65"  firerate="6" />
					<stats rank="A" cost="400"  damage="90"   range="70"  firerate="8" />
				</tower>
				<tower name="Bomb" ground="1" air="0" slow="0" splash="1">
					<stats rank="E" cost="25"   damage="10"   range="90"  firerate="1" />
					<stats rank="D" cost="50"   damage="20"   range="95"  firerate="1" />
					<stats rank="C" cost="75"   damage="40"   range="100" firerate="1" />
					<stats rank="B" cost="100"  damage="80"   range="105" firerate="1" />
					<stats rank="A" cost="300"  damage="160"  range="120" firerate="1" />
				</tower>        
				<tower name="Misslie" ground="0" air="1" slow="0" splash="0">
					<stats rank="E" cost="30"   damage="25"   range="65" firerate="4" />
					<stats rank="D" cost="60"   damage="50"   range="65" firerate="4" />
					<stats rank="C" cost="120"  damage="100"  range="65" firerate="4" />
					<stats rank="B" cost="180"  damage="200"  range="65" firerate="4" />
					<stats rank="A" cost="240"  damage="300"  range="65" firerate="4" />
				</tower>        
				<tower name="Frost" ground="1" air="1" slow="1" splash="1">
					<stats rank="E" cost="50"   damage="10"   range="50" firerate="0.5" />
					<stats rank="D" cost="100"  damage="15"   range="50" firerate="0.7" />
					<stats rank="C" cost="150"  damage="20"   range="55" firerate="0.7" />
					<stats rank="B" cost="200"  damage="25"   range="55" firerate="0.9" />
					<stats rank="A" cost="150"  damage="30"   range="60" firerate="1.0" />
				</tower>        
				<tower name="Vortex" ground="1" air="0" slow="0" splash="1">
					<stats rank="E" cost="100"  damage="150"  range="40" firerate="0.3" />
					<stats rank="D" cost="200"  damage="300"  range="40" firerate="0.3" />
					<stats rank="C" cost="400"  damage="600"  range="40" firerate="0.3" />
					<stats rank="B" cost="600"  damage="1000" range="40" firerate="0.3" />
					<stats rank="A" cost="1000" damage="2000" range="40" firerate="0.3" />
				</tower>        
				<tower name="Laser" ground="1" air="1" slow="0" splash="1">
					<stats rank="E" cost="150"  damage="80"   range="80" firerate="0.3" />
					<stats rank="D" cost="300"  damage="160"  range="80" firerate="0.3" />
					<stats rank="C" cost="450"  damage="320"  range="80" firerate="0.4" />
					<stats rank="B" cost="900"  damage="640"  range="80" firerate="0.4" />
					<stats rank="A" cost="2000" damage="960"  range="80" firerate="0.5" />
				</tower>        
			</towers>
			<enemies>
				<enemy type="Normal" hpbase="2" hpgrow="7" bounty="1" speed="1.0" />
				<enemy type="Immune" hpbase="2" hpgrow="6" bounty="1" speed="1.0" />
				<enemy tyep="Flying" hpbase="2" hpgrow="5" bounty="2" speed="1.0" />
			</enemies>
			<levels>
				<level type="normal" time="20"><spawn num="10" /><spawn num="0" /><spawn num="10" /></level>
			</levels>
			<starts>
				<start x="35" y="400" width="75" height="12"/>
				<start x="275" y="400" width="75" height="12"/>
				<start x="160" y="400" width="64" height="12"/>
			</starts>
			<goals>
				<goal x="10" y="3" /><goal x="10" y="4" />
				<goal x="11" y="4" /><goal x="12" y="4" />
				<goal x="13" y="3" /><goal x="13" y="4" />
			</goals>
		</root>;
		
		// タワーの属性情報を返す
		public static function getTowerAttlibutes(towerName:String):Object {
			var tower:XMLList = Parameter.data.towers.*.(@name == towerName);
			if (tower.length() == 0) { return null; } // 指定した名前のタワーが存在しないならnullを返す
			
			return {
				ground : Boolean(int(tower.@ground)),
				air : Boolean(int(tower.@air)),
				slow : Boolean(int(tower.@slow)),
				splash : Boolean(int(tower.@splash))
			};
		}
		
		// タワーのステータス情報を返す
		public static function getTowerStats(towerName:String, rankNum:int):Object {
			var stats:XML = Parameter.data.towers.*.(@name == towerName).stats[rankNum];
			if (stats == null) { return null; }	// ステータス情報が無いならnullを返す
			
			return {
				rank : stats.@rank,
				cost : stats.@cost,
				damage : stats.@damage,
				range : stats.@range,
				firerate : stats.@firerate
			};
		}
		
		// ゴールの配列を返す
		public static function getGoals():Array {
			var goals:Array = [];
			for each(var g:XML in Parameter.data.goals.*) {
				goals.push(new Goal(new Point(int(g.@x), int(g.@y))));
			}
			return goals;
		}
	}
//}
//package {
	import flash.display.*;
	import flash.filters.*;
	import flash.geom.Matrix;
	import flash.text.*;
	
	//public 
	class ImageFactory {
		private static var _externalImages:Object;			// 外部画像の連想配列
		private static var _enemyImages:Object;				// 敵画像の連想配列
		private static var _towerBase:BitmapData = null;	// タワーの土台
		private static var _cancelMark:BitmapData = null;	// (タワー選択)キャンセルのマーク
		
		// プリローダーを作成、読み込みを開始する
		public static function preload(parentOfProgressBar:DisplayObjectContainer):Preloader {
			initializeEnemyImages();
			
			_externalImages = { };
			return new Preloader(parentOfProgressBar, _externalImages);
		}
		
		// 敵画像の連想配列を初期化する
		private static function initializeEnemyImages():void {
			_enemyImages = { };
			
			var enemyTypes:Array = ["Normal", "Immune", "Flying"];
			for (var i:int = 0; i < enemyTypes.length; i++) {
				_enemyImages[enemyTypes[i]] = ImageFactory.createEnemy(enemyTypes[i]);
			}
		}
		
		// 外部画像を取得する
		public static function getImage(name:String):BitmapData {
			return _externalImages[name];
		}
		
		// 敵画像を取得する
		public static function getEnemy(name:String):BitmapData {
			return _enemyImages[name];
		}
		
		// キャンセルのマークの画像を取得する
		public static function getCancelMark():BitmapData {
			if (_cancelMark == null) {
				_cancelMark = new BitmapData(Parameter.TOWER_IMAGE_SIZE, Parameter.TOWER_IMAGE_SIZE, true, 0x00ffffff);
				
				var shape:Shape = new Shape();
				var center:Number = Parameter.TOWER_IMAGE_SIZE / 2;
				var radius:Number = center - 8;
				shape.graphics.lineStyle(4, 0xff0000);
				shape.graphics.drawCircle(center, center, radius);
				shape.graphics.moveTo(center + (radius * Math.cos(9 * Math.PI / 8)), center + (radius * Math.sin(9 * Math.PI / 8)));
				shape.graphics.lineTo(center + (radius * Math.cos(Math.PI / 8)), center + (radius * Math.sin(Math.PI / 8)));
				_cancelMark.draw(shape);
			}
			
			return _cancelMark;
		}
		
		// タワーの土台の画像を取得する
		public static function getTowerBase():BitmapData {
			if (_towerBase == null) {
				_towerBase = new BitmapData(Parameter.TOWER_SIZE, Parameter.TOWER_SIZE);
				
				var shape:Shape = new Shape();
				shape.graphics.beginFill(0xc0c0c0);
				shape.graphics.drawRect(0, 0, Parameter.TOWER_SIZE, Parameter.TOWER_SIZE);
				shape.graphics.endFill();
				shape.filters = [new BevelFilter(1, 45, 0xffffff, 1, 0x606060, 1, Parameter.TOWER_SIZE / 4, Parameter.TOWER_SIZE / 4, 255)];
				
				_towerBase.draw(shape);
			}
			
			return _towerBase;
		}
		
		// 敵の画像を作成する
		private static function createEnemy(type:String):BitmapData {
			var bitmapData:BitmapData = new BitmapData(Parameter.NODE_SIZE, Parameter.NODE_SIZE, true, 0x00ffffff);
			
			var shape:Shape;
			switch(type) {
				case "Normal": shape = ImageFactory.createNormalEnemy(); break;
				case "Immune": shape = ImageFactory.createImmuneEnemy(); break;
				case "Flying": shape = ImageFactory.createFlyingEnemy(); break;
				default: shape = new Shape();
			}
			
			bitmapData.draw(shape);
			return bitmapData;
		}
		
		private static function createNormalEnemy():Shape {
			var shape:Shape = new Shape();
			
			shape.graphics.beginFill(0xff0000);
			shape.graphics.drawRect(4, 2, 4, 12);
			shape.graphics.drawRect(8, 6, 4, 4);
			shape.graphics.endFill();
			shape.filters = [new GlowFilter(0x880000, 1, 2, 2, 255)];
			
			return shape;
		}
		
		private static function createImmuneEnemy():Shape {
			var shape:Shape = new Shape();
			
			shape.graphics.beginFill(0xff0000);
			shape.graphics.drawCircle(8, 8, 6);
			shape.graphics.endFill();
			shape.filters = [new GlowFilter(0x880000, 1, 2, 2, 255)];
			
			return shape;
		}
		
		private static function createFlyingEnemy():Shape {
			var shape:Shape = new Shape();
			
			shape.graphics.lineStyle(1, 0x880000);
			shape.graphics.beginFill(0xff0000);
			shape.graphics.moveTo(2, 4);
			shape.graphics.lineTo(10, 4);
			shape.graphics.lineTo(14, 8);
			shape.graphics.lineTo(2, 4);
			shape.graphics.endFill();
			
			return shape;
		}
		
		// 普通のテキストを作成する
		public static function createSimpleText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint):TextField {
			return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.CENTER);
		}
		
		// 縁取り付きのテキストを作成する
		public static function createBorderedText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint, borderColor:uint):TextField {
			return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.CENTER, false, true, borderColor);
		}
		
		// スコア表示用のテキストを作成する
		public static function createScoreText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint):TextField {
			return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.RIGHT, true);
		}
		
		// タワーのステータス表示用テキストを作成する
		public static function createStatsText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint):TextField {
			return ImageFactory.createText(posx, posy, width, height, text, fontSize, textColor, TextFieldAutoSize.CENTER, true);
		}
		
		private static function createText(posx:int, posy:int, width:int, height:int, text:String, fontSize:int, textColor:uint, autoSize:String, bold:Boolean = false, border:Boolean = false, borderColor:uint = 0x000000):TextField {
			var textField:TextField = new TextField();
			
			var textFormat:TextFormat = new TextFormat("Arial", fontSize, null, bold);
			textField.defaultTextFormat = textFormat;
			
			textField.text = text;
			textField.x = posx;
			textField.y = posy + Math.ceil((height - (textField.textHeight + 4)) / 2);
			textField.width = Math.max(width, textField.textWidth);
			textField.height = textField.textHeight + 4;
			textField.textColor = textColor;
			if (border) { textField.filters = [new GlowFilter(borderColor, 1, 4, 4)]; }
			
			textField.autoSize = autoSize;
			textField.mouseEnabled = textField.selectable = false;
			
			return textField;
		}
		
		// ウインドウを作成する(FF6っぽいヤツ)
		public static function createWindow(posx:int, posy:int, width:int, height:int):Sprite {
			var sprite:Sprite = new Sprite();
			sprite.x = posx;
			sprite.y = posy;
			
			var matrix:Matrix = new Matrix();
			matrix.createGradientBox(width, height, Math.PI / 2);
			
			sprite.graphics.lineStyle(2);
			sprite.graphics.lineGradientStyle(GradientType.LINEAR, [0xf0f0f0, 0x808080], [1, 1], [0, 255], matrix);
			sprite.graphics.beginGradientFill(GradientType.LINEAR, [0x303090, 0x000030], [1, 1], [0, 255], matrix);
			sprite.graphics.drawRoundRect(1, 1, width - 2, height - 2, 10);
			sprite.graphics.endFill();
			
			return sprite;
		}
		
		// カーソルを描画する
		public static function drawCursor(g:Graphics):void {
			g.lineStyle(1, 0xffffff);
			g.drawRect(0.5, 0.5, Parameter.TOWER_SIZE - 1, Parameter.TOWER_SIZE - 1);
			g.endFill();
		}
		
		// 射程範囲の円を描画する
		public static function drawRangeCircle(g:Graphics, radius:int = 16, color:uint = 0xffffff):void {
			g.beginFill(color, 0.3);
			g.drawCircle(Parameter.TOWER_SIZE / 2, Parameter.TOWER_SIZE / 2, radius);
			g.endFill();
		}
	}
//}
//package {
	import com.bit101.components.ProgressBar;
	import flash.display.DisplayObjectContainer;
	import flash.events.*;
	
	//public
	class Preloader extends EventDispatcher {
		private var _imageNum:int;				// 読み込むべき外部画像の数
		private var _loadedNum:int;				// 読み込み完了した外部画像の数
		private var _loaders:Object;			// 外部画像ローダの連想配列
		private var _imagesReference:Object;	// 外部画像の連想配列の参照
		private var _progressBar:ProgressBar;	// プログレスバー
		
		public function Preloader(parentOfProgressBar:DisplayObjectContainer, images:Object) {
			_imageNum = 0;
			_loadedNum = 0;
			_loaders = { };
			_imagesReference = images;
			_progressBar = new ProgressBar(parentOfProgressBar, 182, 227);
			
			// 各外部画像の読み込みを開始する
			for (var imageName:* in Parameter.EXTERNAL_IMAGES) {
				_imageNum++;
				var loader:ExternalImageLoader = new ExternalImageLoader();
				_loaders[imageName] = loader;
				loader.addEventListener(Event.COMPLETE, imageLoaded);
				loader.load(Parameter.EXTERNAL_IMAGES[imageName]);
			}
			_progressBar.maximum = _imageNum;
		}
		
		// 一つの画像の読み込みが完了した際に呼ばれるメソッド
		private function imageLoaded(e:Event):void {
			e.target.removeEventListener(Event.COMPLETE, imageLoaded);
			
			_loadedNum++;
			_progressBar.value = _loadedNum;
			if (_loadedNum == _imageNum) { loadComplete(); }
		}
		
		// 全ての画像の読み込みが完了した際に呼ばれるメソッド
		private function loadComplete():void {
			for (var imageName:* in _loaders) {
				_imagesReference[imageName] = _loaders[imageName].content;
			}
			
			DisplayObjectContainer(_progressBar.parent).removeChild(_progressBar);
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}
//}
//package {
	import flash.display.*;
	import flash.events.*;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	
	//public
	class ExternalImageLoader extends EventDispatcher {
		private var _content:BitmapData;
		private var _tmpA:Loader;
		private var _tmpB:Loader;
		
		public function get content():BitmapData { return _content; }
		
		public function ExternalImageLoader() {
			_content = null;
			_tmpA = new Loader();
			_tmpB = new Loader();
		}
		
		public function load(url:String):void {
			_tmpA.contentLoaderInfo.addEventListener(Event.INIT, tmpALoaded);
			_tmpA.load(new URLRequest(url), new LoaderContext(true));
		}
		
		private function tmpALoaded(e:Event):void {
			_tmpA.contentLoaderInfo.removeEventListener(Event.INIT, tmpALoaded);
			_content = new BitmapData(int(_tmpA.width), int(_tmpA.height), true, 0x00ffffff);
			_tmpB.contentLoaderInfo.addEventListener(Event.INIT, tmpBLoaded);
			_tmpB.loadBytes(_tmpA.contentLoaderInfo.bytes);
		}
		
		private function tmpBLoaded(e:Event):void {
			_tmpB.contentLoaderInfo.removeEventListener(Event.INIT, tmpBLoaded);
			_content.draw(_tmpB);
			_tmpA.unload();
			_tmpB.unload();
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}
//}
//package {
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	//public
	class FieldMap extends Sprite {
		private var _groundEnemyLayer:Sprite;
		private var _towerLayer:Sprite;
		private var _airEnemyLayer:Sprite;
		private var _bulletLayer:Sprite;
		private var _cursor:Sprite;
		
		public function FieldMap(posx:int, posy:int) {
			x = posx;
			y = posy;
			
			addChild(new Bitmap(ImageFactory.getImage("Fieldmap")));
			addChild(_groundEnemyLayer = new Sprite());
			addChild(_towerLayer = new Sprite());
			addChild(_airEnemyLayer = new Sprite());
			addChild(_bulletLayer = new Sprite());
			addChild(_cursor = new Sprite());
			_bulletLayer.mouseEnabled = _cursor.mouseEnabled = false;
			_cursor.visible = false;
			
			addEventListener(MouseEvent.CLICK, clickFieldMap);
			addEventListener(MouseEvent.ROLL_OVER, showCursor);
			addEventListener(MouseEvent.ROLL_OUT, hideCursor);
			
			//test
			var e:Enemy = new Enemy(new Point(40, 390), { hp:1, bounty:1, speed:1 } );
			Main.enemies.push(e);
			_groundEnemyLayer.addChild(e);
			addEventListener(Event.ENTER_FRAME, test);
		}
		
		private function test(e:Event):void {
			for (var i:int = 0; i < Main.towers.length; i++) {
				Main.towers[i].update();
			}
			for (var j:int = 0; j < Main.enemies.length; j++) {
				Main.enemies[j].update();
			}
		}
		
		private function clickFieldMap(e:MouseEvent):void {
			var data:GameData = GameData.instance;
			
			var selectedTower:Tower = data.selectedTower;
			if (selectedTower != null && !selectedTower.active) {
				if (Node.buildable(_cursor.x, _cursor.y) && data.buyable(selectedTower.cost) && Goal.reSearch(Node.tileFromPosition(new Point(_cursor.x,_cursor.y)))) {
					var tower:Tower = new Tower(_cursor.x, _cursor.y, data.selectedTower.towerName, true);
					data.spendGold(selectedTower.cost);
					Main.towers.push(tower);
					_towerLayer.addChild(tower);
				}
			}
		}
		
		private function showCursor(e:MouseEvent):void {
			_cursor.visible = true;
			addEventListener(Event.ENTER_FRAME, updateCursor);
		}
		
		private function hideCursor(e:MouseEvent):void {
			removeEventListener(Event.ENTER_FRAME, updateCursor);
			_cursor.visible = false;
		}
		
		private function updateCursor(e:Event):void {
			var selectedTower:Tower = GameData.instance.selectedTower;
			
			if(!(selectedTower != null && selectedTower.active)){
				_cursor.x = mouseX - (mouseX % Parameter.NODE_SIZE);
				_cursor.y = mouseY - (mouseY % Parameter.NODE_SIZE);
			}else {
				_cursor.x = selectedTower.x;
				_cursor.y = selectedTower.y;
			}
			
			_cursor.graphics.clear();
			if (selectedTower != null) {
				ImageFactory.drawRangeCircle(_cursor.graphics, selectedTower.range, 0xffffff);
				ImageFactory.drawCursor(_cursor.graphics);
			}
		}
	}
//}
//package {
	import com.bit101.components.*;
	import flash.display.*;
	import flash.events.*;
	import flash.text.*;
	
	//public 
	class Frontend extends Sprite {
		private var _level:TextField;
		private var _score:TextField;
		private var _lives:TextField;
		private var _gold:TextField;
		
		private var _towerStatsWindow:Sprite;
		private var _towerMenuWindow:Sprite;
		private var _name:TextField;
		private var _attlibuteGround:TextField;
		private var _attlibuteAir:TextField;
		private var _attlibuteSlow:TextField;
		private var _attlibuteSplash:TextField;
		private var _rank:TextField;
		private var _cost:TextField;
		private var _damage:TextField;
		private var _range:TextField;
		private var _fireRate:TextField;
		
		public function Frontend() {
			setupMainStatsWindow();
			setupTowerSelectWindow();
			setupTowerStatsWindow();
			setupLevelBarWindow();
			setupMenuWindow();
			
			GameData.instance.addEventListener(Event.CHANGE, update);
		}
		
		// メインステータスを表示するウインドウを配置する
		private function setupMainStatsWindow():void {
			var mainStatsWindow:Sprite = ImageFactory.createWindow(0, 0, 365, 25);
			
			mainStatsWindow.addChild(ImageFactory.createBorderedText(14, 0, 40, 25, "Level :", 12, 0xffffff, 0x808080));
			mainStatsWindow.addChild(_level = ImageFactory.createScoreText(54, 0, 25, 25, "0", 14, 0xffffff));
			
			mainStatsWindow.addChild(ImageFactory.createBorderedText(93, 0, 40, 25, "Score :", 12, 0xffffff, 0x808080));
			mainStatsWindow.addChild(_score = ImageFactory.createScoreText(133, 0, 50, 25, "0", 14, 0xffffff));
			
			mainStatsWindow.addChild(ImageFactory.createBorderedText(197, 0, 40, 25, "Lives :", 12, 0xffffff, 0xf00000));
			mainStatsWindow.addChild(_lives = ImageFactory.createScoreText(237, 0, 20, 25, Parameter.INITIAL_LIVES.toString(), 14, 0xff0000));
			
			mainStatsWindow.addChild(ImageFactory.createBorderedText(271, 0, 35, 25, "Gold :", 12, 0xffffff, 0xb0b000));
			mainStatsWindow.addChild(_gold = ImageFactory.createScoreText(306, 0, 45, 25, Parameter.INITIAL_GOLD.toString(), 14, 0xffff00));
			
			addChild(mainStatsWindow);
		}
		
		// タワーを選択するウインドウを配置する
		private function setupTowerSelectWindow():void {
			var towerSelectWindow:Sprite = ImageFactory.createWindow(365, 0, 100, 415);
			
			var towerNames:Array = ["Arrow", "Gatling", "Bomb", "Misslie", "Frost", "Vortex", "Laser", "Cancel"];
			for (var i:int = 0; i < 8; i++) {
				var tower:Tower = new Tower(((i < 4) ? 15 : 53), (7 + 38 * (i % 4)), towerNames[i], false);
				towerSelectWindow.addChild(tower);
				
				if (i < 7) { towerSelectWindow.addChild(ImageFactory.createSimpleText(((i < 4) ? 1 : 85), tower.y, 14, 32, String(i + 1), 10, 0xffffff)); }
			}
			
			addChild(towerSelectWindow);
		}
		
		// タワーのステータスを表示するウインドウを作成する
		private function setupTowerStatsWindow():void {
			_towerStatsWindow = ImageFactory.createWindow(370, 160, 90, 250);
			
			_towerStatsWindow.addChild(ImageFactory.createWindow(0, 0, 90, 20));
			_towerStatsWindow.addChild(_name = ImageFactory.createSimpleText(0, 0, 90, 20, "Tower", 12, 0xffffff));
			
			_towerStatsWindow.addChild(_attlibuteGround = ImageFactory.createSimpleText(5, 25, 40, 10, "Ground", 10, 0xffffff));
			_towerStatsWindow.addChild(_attlibuteAir = ImageFactory.createSimpleText(5, 35, 40, 10, "Air", 10, 0xffffff));
			_towerStatsWindow.addChild(_attlibuteSlow = ImageFactory.createSimpleText(45, 25, 40, 10, "Slow", 10, 0x606060));
			_towerStatsWindow.addChild(_attlibuteSplash = ImageFactory.createSimpleText(45, 35, 40, 10, "Splash", 10, 0x606060));
			
			_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 50, 90, 10, "Rank", 10, 0xffffff, 0x00b000));
			_towerStatsWindow.addChild(_rank = ImageFactory.createStatsText(0, 62, 90, 15, "E", 14, 0x00ff00));
			
			_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 80, 90, 10, "Cost", 10, 0xffffff, 0xb0b000));
			_towerStatsWindow.addChild(_cost = ImageFactory.createStatsText(0, 92, 90, 15, "0", 14, 0xffff00));
			
			_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 110, 90, 10, "Damage", 10, 0xffffff, 0xf00000));
			_towerStatsWindow.addChild(_damage = ImageFactory.createStatsText(0, 122, 90, 15, "0", 14, 0xff0000));
			
			_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 140, 90, 10, "Range", 10, 0xffffff, 0x00b0b0));
			_towerStatsWindow.addChild(_range = ImageFactory.createStatsText(0, 152, 90, 15, "0", 14, 0x00ffff));
			
			_towerStatsWindow.addChild(ImageFactory.createBorderedText(0, 170, 90, 10, "FireRate", 10, 0xffffff, 0xb000b0));
			_towerStatsWindow.addChild(_fireRate = ImageFactory.createStatsText(0, 182, 90, 15, "0", 14, 0xff00ff));
			
			_towerStatsWindow.addChild(_towerMenuWindow = ImageFactory.createWindow(0, 200, 90, 50));
			var upgradeButton:PushButton = new PushButton(_towerMenuWindow, 5, 5, "Upgrade", clickUpdateButton);
			var sellButton:PushButton = new PushButton(_towerMenuWindow, 5, 25, "Sell", clickSellButton);
			upgradeButton.width = sellButton.width = 80;
			
			addChild(_towerStatsWindow);
			_towerStatsWindow.visible = false;
		}
		
		private function clickUpdateButton(e:MouseEvent):void {
			GameData.instance.selectedTower.upgrade();
			GameData.instance.setSelectedTower(GameData.instance.selectedTower);
		}
		
		// 売却ボタンを押した時の処理
		private function clickSellButton(e:MouseEvent):void {
			GameData.instance.selectedTower.sell();
			GameData.instance.setSelectedTower(null);
		}
		
		// レベルバーを表示するウインドウを配置する
		private function setupLevelBarWindow():void {
			var levelBarWindow:Sprite = ImageFactory.createWindow( -10, 415, 475, 50);
			
			/*
			var backgroundBar:Shape = new Shape();
			backgroundBar.graphics.beginFill(0x000000);
			backgroundBar.graphics.drawRect(0, 10, 475, 30);
			backgroundBar.graphics.endFill();
			levelBarWindow.addChild(backgroundBar);
			
			var hand:Shape = new Shape();
			hand.graphics.lineStyle(1, 0xffff00);
			hand.graphics.moveTo(45, 2);
			hand.graphics.lineTo(45, 48);
			levelBarWindow.addChild(hand);
			*/
			
			addChild(levelBarWindow);
		}
		
		// メニューウインドウを配置する
		private function setupMenuWindow():void {
			var menuWindow:Sprite = ImageFactory.createWindow(365, 415, 100, 50);
			
			//var pauseButton:PushButton = new PushButton(menuWindow, 5, 4, "Pause", null);
			//var nextLevelButton:PushButton = new PushButton(menuWindow, 5, 26, "Next Level", null);
			//pauseButton.width = nextLevelButton.width = 90;
			
			addChild(menuWindow);
		}
		
		// ゲーム情報の更新を反映する
		public function update(e:Event):void {
			updateMainStatsWindow();
			updateTowerStatsWindow();
		}
		
		// メインステータス表示を更新する
		private function updateMainStatsWindow():void {
			var data:GameData = GameData.instance;
			_level.text = data.level.toString();
			_score.text = data.score.toString();
			_lives.text = data.lives.toString();
			_gold.text = data.gold.toString();
		}
		
		// タワーのステータス表示を更新する
		private function updateTowerStatsWindow():void {
			_towerStatsWindow.visible = (GameData.instance.selectedTower != null);
			if (_towerStatsWindow.visible) {
				var selectedTower:Tower = GameData.instance.selectedTower;
				
				_towerMenuWindow.visible = selectedTower.active;
				_name.text = selectedTower.towerName + " Tower";
				var onColor:uint = 0xffffff;
				var offColor:uint = 0x606060;
				_attlibuteGround.textColor = (selectedTower.ground ? onColor : offColor);
				_attlibuteAir.textColor = (selectedTower.air ? onColor : offColor);
				_attlibuteSlow.textColor = (selectedTower.slow ? onColor : offColor);
				_attlibuteSplash.textColor = (selectedTower.splash ? onColor : offColor);
				
				_rank.text = selectedTower.rank + ((selectedTower.active && selectedTower.hasNextRank()) ? (" → " + selectedTower.nextRank) : "");
				_cost.text = selectedTower.cost + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextCost - selectedTower.cost)) : "");
				_damage.text = selectedTower.damage + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextDamage - selectedTower.damage)) : "");
				_range.text = selectedTower.range + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextRange - selectedTower.range)) : "");
				_fireRate.text = selectedTower.fireRate.toFixed(1) + ((selectedTower.active && selectedTower.hasNextRank()) ? (" + " + (selectedTower.nextFireRate - selectedTower.fireRate).toFixed(1)) : "");
			}
		}
	}
//}
//package {
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.geom.Point;
	
	//public 
	class GameData extends EventDispatcher {
		private static var _instance:GameData;
		
		private var _selectedTower:Tower;
		
		private var _level:int;
		private var _score:int;
		private var _lives:int;
		private var _gold:int;
		
		public function get selectedTower():Tower { return _selectedTower; }
		public function get level():int { return _level; }
		public function get score():int { return _score; }
		public function get lives():int { return _lives; }
		public function get gold():int { return _gold; }
		
		public function GameData(enforcer:SingletonEnforcer) {
			initialize();
		}
		
		public function initialize():void {
			_level = 0;
			_score = 0;
			_lives = Parameter.INITIAL_LIVES;
			_gold = Parameter.INITIAL_GOLD;
			
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		// 選択中のタワーを設定する
		public function setSelectedTower(tower:Tower):void {
			_selectedTower = tower;
			
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		public function damageLives():void {
			_lives--;
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		// 購入できるかどうか
		public function buyable(price:int):Boolean {
			return price <= _gold;
		}
		
		// ゴールドを得る
		public function earnGold(amount:int):void {
			_gold += amount;
			
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		// ゴールドを消費する
		public function spendGold(amount:int):void {
			_gold -= amount;
			
			dispatchEvent(new Event(Event.CHANGE));
		}
		
		public static function get instance():GameData {
			if (GameData._instance == null) {
				_instance = new GameData(new SingletonEnforcer());
			}
			
			return _instance;
		}
	}
//}
class SingletonEnforcer { }
//package {
	import flash.geom.Point;
	
	//public 
	class Node {
		private var _tile:Point;
		private var _center:Point;
		
		private var _passable:Boolean;	// 敵が通れるかどうか
		private var _buildable:Boolean;	// タワーが建てられるかどうか
		private var _enemyNum:int;		// このノード上にいる敵の数
		
		public function get tileX():int { return _tile.x; }
		public function get tileY():int { return _tile.y; }
		public function get centerX():Number { return _center.x; }
		public function get centerY():Number { return _center.y; }
		
		public function get passable():Boolean { return _passable; }
		public function set passable(value:Boolean):void { _passable = value; }
		
		public function get buildable():Boolean { return _buildable && (_enemyNum == 0); }
		public function set buildable(value:Boolean):void { _buildable = value; };
		
		public function get enemyNum():int { return _enemyNum; }
		public function set enemyNum(value:int):void { _enemyNum = value; }
		
		public function Node(tilex:int, tiley:int, type:int) {
			_tile = new Point(tilex, tiley);
			var pos:Point = Node.positionFromTile(_tile);
			_center = new Point(pos.x + (Parameter.NODE_SIZE / 2), pos.y +(Parameter.NODE_SIZE / 2));
			switch(type) {
				case 0: _passable = true; _buildable = true; break;
				case 1: _passable = false; _buildable = false; break;
				case 2: _passable = true; _buildable = false; break;
			}
			_enemyNum = 0;
		}
		
		// タイル縦横値から、XY座標値を求める
		public static function positionFromTile(tile:Point):Point {
			var pos:Point = new Point();
			
			pos.x = tile.x * Parameter.NODE_SIZE;
			pos.x = Math.max(0, Math.min(pos.x, (Parameter.NODE_COLS - 1) * Parameter.NODE_SIZE));
			pos.y = tile.y * Parameter.NODE_SIZE;
			pos.y = Math.max(0, Math.min(pos.y, (Parameter.NODE_ROWS - 1) * Parameter.NODE_SIZE));
			
			return pos;
		}
		
		// XY座標値から、タイル縦横値を求める
		public static function tileFromPosition(pos:Point):Point {
			var tile:Point = new Point();
			
			tile.x = int(pos.x / Parameter.NODE_SIZE);
			tile.x = Math.max(0, Math.min(tile.x, Parameter.NODE_COLS - 1));
			tile.y = int(pos.y / Parameter.NODE_SIZE);
			tile.y = Math.max(0, Math.min(tile.y, Parameter.NODE_ROWS - 1));
			
			return tile;
		}
		
		// タワーが設置できるかどうか
		public static function buildable(posx:int, posy:int):Boolean {
			var tile:Point = Node.tileFromPosition(new Point(posx, posy));
			
			return (Main.nodes[tile.y][tile.x].buildable &&
			Main.nodes[tile.y + 1][tile.x].buildable &&
			Main.nodes[tile.y][tile.x + 1].buildable &&
			Main.nodes[tile.y + 1][tile.x + 1].buildable);
		}
		
		public static function changeBulidablity(towerTile:Point, buildable:Boolean):void {
			Main.nodes[towerTile.y][towerTile.x].buildable = buildable;
			Main.nodes[towerTile.y + 1][towerTile.x].buildable = buildable;
			Main.nodes[towerTile.y][towerTile.x + 1].buildable = buildable;
			Main.nodes[towerTile.y + 1][towerTile.x + 1].buildable = buildable;
		}
		
		public static function changePassablity(towerTile:Point, passable:Boolean):void {
			Main.nodes[towerTile.y][towerTile.x].passable = passable;
			Main.nodes[towerTile.y + 1][towerTile.x].passable = passable;
			Main.nodes[towerTile.y][towerTile.x + 1].passable = passable;
			Main.nodes[towerTile.y + 1][towerTile.x + 1].passable = passable;
		}
	}
//}
//package {
	import flash.geom.Point;
	
	//public 
	class Goal {
		private static const DX:Array = [0, -1, 1, 0, -1, 1, -1, 1];
		private static const DY:Array = [ -1, 0, 0, 1, -1, -1, 1, 1];
		private static const DCOST:Array = [1, 1, 1, 1, Math.SQRT2, Math.SQRT2, Math.SQRT2, Math.SQRT2];
		
		private var _node:Node;
		private var _openNodes:Array;			// 保留ノードリスト
		private var _nodeCost:Array;			// 各ノードの移動コスト
		private var _nodeNext:Array;			// 各ノードの次の経路となるノード
		private var _previousNodeCost:Array;	// 以前のnodeCost
		private var _previousNodeNext:Array;	// 以前のnodeNext
		
		public function get node():Node { return _node; }
		public function getCost(tile:Point):Number { return _nodeCost[tile.y][tile.x]; }
		public function getNext(tile:Point):Node { return _nodeNext[tile.y][tile.x]; }
		
		public function Goal(tile:Point) {
			_node = Main.nodes[tile.y][tile.x];
			_openNodes = [];
			_nodeCost = _nodeNext = null;
			
			search();
		}
		
		// ダイクストラ法による経路探索
		public function search():void {
			initialize();
			
			while (_openNodes.length > 0) {
				var subject:Node = _openNodes.pop() as Node;
				
				// 周囲8方向のノードを訪問する
				for (var i:int = 0; i < 8; i++) {
					// 画面外の存在しないノードを指すなら次の周囲ノードへ進む
					if (!isValid(subject.tileX + Goal.DX[i], subject.tileY + Goal.DY[i])) { continue; }
					// 通れないノード、計算済み(確定)ノード、直進することができないノードなら次の周囲ノードへ進む
					var test:Node = Main.nodes[subject.tileY + Goal.DY[i]][subject.tileX + Goal.DX[i]];
					if (isImpassable(test) || isCalculatedNode(test) || !canGoStraightTo(subject, test)) { continue; }
					
					// 移動コストを計算する
					_nodeCost[test.tileY][test.tileX] = _nodeCost[subject.tileY][subject.tileX] + Goal.DCOST[i];
					// 次の経路ノードをsubjectノードに設定する
					_nodeNext[test.tileY][test.tileX] = subject;
					// 保留ノードリストに追加する
					insertToOpenNodes(test);
				}
			}
		}
		
		private function initialize():void {
			_previousNodeCost = _nodeCost;
			_previousNodeNext = _nodeNext;
			
			_nodeCost = [];
			_nodeNext = [];
			for (var row:int = 0; row < Parameter.NODE_ROWS; row++) {
				_nodeCost[row] = [];
				_nodeNext[row] = [];
				for (var col:int = 0; col < Parameter.NODE_COLS; col++) {
					_nodeCost[row][col] = Number.MAX_VALUE;
					_nodeNext[row][col] = Main.nodes[row][col];
				}
			}
			
			// Goalのノードを経路探索のスタートノードとする
			_nodeCost[_node.tileY][_node.tileX] = 0;
			_openNodes.push(_node);
		}
		
		// indexの値が有効な値かどうか
		private function isValid(col:int, row:int):Boolean {
			return ((col >= 0) && (col < Parameter.NODE_COLS) && (row >= 0) && (row < Parameter.NODE_ROWS));
		}
		
		// 既にコストを計算済みのノードかどうか
		private function isCalculatedNode(node:Node):Boolean {
			return _nodeCost[node.tileY][node.tileX] != Number.MAX_VALUE;
		}
		
		// 通れないノードかどうか
		private function isImpassable(node:Node):Boolean {
			return !node.passable;
		}
		
		// subjectノードからtestノードへ直進できるかどうか
		private function canGoStraightTo(subject:Node, test:Node):Boolean {
			return (Main.nodes[subject.tileY][test.tileX].passable && Main.nodes[test.tileY][subject.tileX].passable);
		}
		
		// nodeを保留ノードリストの適切な場所に挿入する
		private function insertToOpenNodes(node:Node):void {
			var insertIndex:int;
			var len:int = _openNodes.length;
			var nodeCost:Number = _nodeCost[node.tileY][node.tileX];
			
			for (insertIndex = 0; insertIndex < len; insertIndex++) {
				var openNode:Node = _openNodes[insertIndex];
				if (nodeCost > _nodeCost[openNode.tileY][openNode.tileX]) { break; }
			}
			_openNodes.splice(insertIndex, 0, node);
		}
		
		// 一つ前の状態を復元する
		public function revertToPrevious():void {
			_nodeCost = _previousNodeCost;
			_nodeNext = _previousNodeNext;
		}
		
		// 指定した位置から最も近いゴールを取得する
		public static function getNearestGoalFrom(tile:Point):Goal {
			var goals:Array = Main.goals;
			var nearest:Goal = goals[0];
			
			var len:int = goals.length;
			for (var i:int = 1; i < len; i++) {
				if (goals[i].getCost(tile) < nearest.getCost(tile)) {
					nearest = goals[i];
				}
			}
			
			return nearest;
		}
		
		// 最探索し、成功したかどうかを返す
		public static function reSearch(towerTile:Point):Boolean {
			Node.changePassablity(towerTile, false);
			
			var i:int;
			for (i = 0; i < Main.goals.length; i++) {
				Main.goals[i].search();
			}
			
			var hasPathAllEnemy:Boolean = true;
			for (i = 0; i < Main.enemies.length; i++) {
				Main.enemies[i].updateNearestGoal();
				
				if (!Main.enemies[i].hasPathToGoal()) {
					hasPathAllEnemy = false;
					break;
				}
			}
			
			Node.changePassablity(towerTile, true);
			if (hasPathAllEnemy) {
				return true;
			// ブロッキングしていたら全部元に戻す
			}else {
				for (i = 0; i < Main.goals.length; i++) {
					Main.goals[i].revertToPrevious();
				}
				
				for (i = 0; i < Main.enemies.length; i++) {
					Main.enemies[i].updateNearestGoal();
				}
				
				return false;
			}
		}
	}
//}
//package {
	import flash.display.*;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	//public 
	class Tower extends Sprite {
		private var _center:Point;
		
		private var _name:String;
		private var _rank:int;
		private var _attlibutes:Object;
		private var _currentStats:Object;
		private var _nextStats:Object;
		private var _active:Boolean;
		
		private var _target:Enemy;
		private var _reloadSpeed:Number;	// 毎フレームのカウントの上昇値
		private var _reloadCount:Number;	// この値が100を超えたら発射可能
		
		private var _image:Sprite;
		
		public function get towerName():String { return _name; }
		
		public function get ground():Boolean { return _attlibutes.ground; }
		public function get air():Boolean { return _attlibutes.air; }
		public function get slow():Boolean { return _attlibutes.slow; }
		public function get splash():Boolean { return _attlibutes.splash; }
		
		public function get rank():String { return _currentStats.rank; }
		public function get cost():int { return _currentStats.cost; }
		public function get damage():int { return _currentStats.damage; }
		public function get range():int { return _currentStats.range; }
		public function get fireRate():Number { return _currentStats.firerate; }
		
		public function get nextRank():String { return _nextStats.rank; }
		public function get nextCost():int { return _nextStats.cost; }
		public function get nextDamage():int { return _nextStats.damage; }
		public function get nextRange():int { return _nextStats.range; }
		public function get nextFireRate():Number { return _nextStats.firerate; }
		
		public function get active():Boolean { return _active; }
		
		public function Tower(posx:int, posy:int, name:String, active:Boolean) {
			x = posx;
			y = posy;
			
			_center = new Point(posx + Parameter.TOWER_SIZE / 2, posy + Parameter.TOWER_SIZE / 2);
			_name = name;
			_rank = 0;
			_attlibutes = Parameter.getTowerAttlibutes(_name);
			_currentStats = Parameter.getTowerStats(_name, _rank);
			_nextStats = Parameter.getTowerStats(_name, _rank + 1);
			_active = active;
			
			if (active) {
				_target = null;
				_reloadSpeed = _currentStats.firerate * 100 / Parameter.FRAMERATE; 
				_reloadCount = 0;
				
				var tile:Point = Node.tileFromPosition(new Point(x, y));
				Node.changePassablity(tile, false);
				Node.changeBulidablity(tile, false);
			}
			
			draw();
			
			buttonMode = true;
			addEventListener(MouseEvent.CLICK, selected);
		}
		
		// タワーの画像を描画する
		private function draw():void {
			addChild(new Bitmap(ImageFactory.getTowerBase()));
			
			_image = new Sprite();
			var bitmap:Bitmap = new Bitmap((_name != "Cancel") ? ImageFactory.getImage(_name) : ImageFactory.getCancelMark(), "auto", true);
			bitmap.x = bitmap.y = int( -Parameter.TOWER_IMAGE_SIZE / 2);
			_image.x  = _image.y = int(Parameter.TOWER_SIZE / 2);
			_image.addChild(bitmap);
			addChild(_image);
			
			if (active) { _image.rotation = int(350 * Math.random() - 175); }
		}
		
		public function update():void {
			// ターゲット無しかターゲットがやられていたら、新しいターゲットを探す
			if (_target == null || _target.hp <= 0) {
				for (var i:int = 0; i < Main.enemies.length; i++) {
					var diffX:Number = _center.x - Main.enemies[i].posX;
					var diffY:Number = _center.y - Main.enemies[i].posY;
					if (Math.sqrt(diffX * diffX + diffY * diffY) < _currentStats.range) {
						_target = Main.enemies[i];
						break;
					}
				}
			}
			
			// ターゲットがいるなら、
			// 射程内ならターゲットの方を向き、射程外ならターゲットからはずす
			if (_target != null) {
				diffX = _target.posX - _center.x;
				diffY = _target.posY - _center.y;
				if (Math.sqrt(diffX * diffX + diffY * diffY) < _currentStats.range) {
					var degree:Number = Math.atan2(diffY, diffX) * 180 / Math.PI;
					_image.rotation = degree;
				}else {
					_target = null;
				}
			}
			
			// 弾を発射できるなら発射する
			_reloadCount += _reloadSpeed;
		}
		
		// タワーアップグレード時の処理
		public function upgrade():void {
			if (hasNextRank() && GameData.instance.buyable(_nextStats.cost - _currentStats.cost)) {
				GameData.instance.spendGold(_nextStats.cost - _currentStats.cost);
				
				_rank++;
				_currentStats = _nextStats;
				_nextStats = Parameter.getTowerStats(_name, _rank + 1);
				
				_reloadSpeed = _currentStats.firerate * 100 / Parameter.FRAMERATE;
			}
		}
		
		// 次のランクがあるかどうか
		public function hasNextRank():Boolean {
			return _nextStats != null;
		}
		
		// タワー売却時の処理
		public function sell():void {
			parent.removeChild(this);
			var tile:Point = Node.tileFromPosition(new Point(x, y));
			Node.changePassablity(tile, true);
			Node.changeBulidablity(tile, true);
			Main.towers.splice(Main.towers.indexOf(this), 1);
			GameData.instance.earnGold(int(_currentStats.cost * Parameter.TOWER_SELL_RATE));
		}
		
		private function selected(e:MouseEvent):void {
			GameData.instance.setSelectedTower((_name != "Cancel") ? this : null);
		}
	}
//}
//package {
	import flash.display.*;
	import flash.geom.Point;
	
	//public 
	class Enemy extends Sprite {
		private var _position:Point;
		private var _velocity:Point;
		
		private var _hp:int;			// ヒットポイント
		private var _bounty:int;		// 倒して得る金
		private var _speed:Number;		// 速さ(スカラー)
		
		private var _immunity:Boolean;	// 免疫が有るか
		private var _slowing:int;		// スロー状態かどうか
		private var _isFlying:Boolean;	// 飛行しているか
		
		private var _currentNode:Node;	// 現在のノード
		private var _nearestGoal:Goal;	// 最短で到達できるゴールノード
		private var _nextNode:Node;		// 次に進むべきノード
		
		private var _image:Sprite;
		
		public function get posX():Number { return _position.x; }
		public function get posY():Number { return _position.y; }
		public function get hp():int { return _hp; }
		
		public function Enemy(pos:Point, stats:Object) {
			_position = pos;
			
			_hp = stats.hp;
			_bounty = stats.bounty;
			_speed = stats.speed;
			
			_immunity = false;
			_slowing = 0;
			_isFlying = false;
			
			initializeVelocity();
			
			var tile:Point = Node.tileFromPosition(_position);
			initializeCurrentNode(tile);
			initializeNearestGoal(tile);
			initializeNextNode(tile);
			
			draw();
		}
		
		private function initializeVelocity():void {
			if (_isFlying) {
				_velocity = new Point(0, -_speed);
			}else {
				_velocity = new Point();
			}
		}
		
		private function initializeCurrentNode(tile:Point):void {
			_currentNode = Main.nodes[tile.y][tile.x];
			if (!_isFlying) { _currentNode.enemyNum++; }
		}
		
		private function initializeNearestGoal(tile:Point):void {
			if (_isFlying) {
				_nearestGoal = Main.nodes[4][tile.x];
			}else {
				_nearestGoal = Goal.getNearestGoalFrom(tile);
			}
		}
		
		private function initializeNextNode(tile:Point):void {
			if (_isFlying) {
				_nextNode = _nearestGoal.node;
			}else {
				_nextNode = _nearestGoal.getNext(tile);
			}
		}
		
		private function draw():void {
			_image = new Sprite();
			var bitmap:Bitmap = new Bitmap(ImageFactory.getEnemy("Normal"));
			bitmap.x = bitmap.y = int( -Parameter.NODE_SIZE / 2);
			_image.rotation = -90;
			_image.addChild(bitmap);
			addChild(_image);
		}
		
		public function update():void {
			if (_hp <= 0) {
				GameData.instance.earnGold(_bounty);
				vanish();
				return;
			}
			
			var tile:Point = Node.tileFromPosition(_position);
			
			// ゴールに着いたら、ライフが減って敵消滅
			if (arrivedGoal(tile)) {
				GameData.instance.damageLives();
				vanish();
				return;
			}
			
			move(tile);
			veer(tile);
		}
		
		// 消滅する
		private function vanish():void {
			if (!_isFlying) { _currentNode.enemyNum--; }
			parent.removeChild(this);
			Main.enemies.splice(Main.enemies.indexOf(this), 1);
		}
		
		// 移動する
		private function move(tile:Point):void {
			var slowed:Boolean = (_slowing > 0);
			if (slowed) { _slowing--; }
			
			x = (_position.x += (slowed ? _velocity.x / 2 : _velocity.x));
			y = (_position.y += (slowed ? _velocity.y / 2 : _velocity.y));
		}
		
		// 進行方向の修正
		private function veer(tile:Point):void {
			if (!_isFlying) {
				//次に進むべきノードへ到着していたら、次に進むべきノードを更新する
				if (arrivedNextNode(tile)) {
					_currentNode.enemyNum--;
					_nextNode.enemyNum++;
					
					_currentNode = _nextNode;
					updateNextNode(tile); 
				}
				
				var radian:Number = Math.atan2(_nextNode.centerY - _position.y, _nextNode.centerX - _position.x);
				_velocity.x = (_velocity.x + _speed * Math.cos(radian)) * 0.5;
				_velocity.y = (_velocity.y + _speed * Math.sin(radian)) * 0.5;
				
				var degree:Number = radian * 180 / Math.PI;
				_image.rotation = degree;
			}
		}
		
		// 最短で到達できるゴールノードを更新する
		public function updateNearestGoal():void {
			var tile:Point = Node.tileFromPosition(_position);
			_nearestGoal = Goal.getNearestGoalFrom(tile);
			
			updateNextNode(tile);
		}
		
		// 次に進むべきノードを更新する
		private function updateNextNode(tile:Point):void {
			_nextNode = _nearestGoal.getNext(tile);
		}
		
		// ゴールへ向かう経路が存在しているかどうか
		public function hasPathToGoal():Boolean {
			return _currentNode != _nextNode;
		}
		
		// ゴールノードへ到着しているかどうか
		private function arrivedGoal(tile:Point):Boolean {
			return (tile.x == _nearestGoal.node.tileX) && (tile.y == _nearestGoal.node.tileY);
		}
		
		// 次に進むべきノードへ到着しているかどうか
		private function arrivedNextNode(tile:Point):Boolean {
			return  (tile.x == _nextNode.tileX) && (tile.y == _nextNode.tileY);
		}
		
		// ダメージを受ける
		public function damaged(amount:int, slow:Boolean):void {
			_hp -= amount;
			if (slow) { slowed(); }
		}
		
		// 移動が遅くなる(免疫が無ければ)
		private function slowed():void {
			if (!_immunity) { _slowing = Parameter.SLOWING_TIME; }
		}
	}
//}