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

Left 2 Die - Zombie Mayhem (Single player version)

...
* @author Swingpants
*
* Left 2 Die - "Zombie Mayhem"
* An exercise in cooperative play
* 
* Built for the Moock Checkmate Challenge - ran out of time - misjudged when deadline was
* 
* This is a single player version
* 
* Aim of game take your team to the safe house (top left corner)
* Got to stay together to survive
*
* To Do:
*
* Register death
* Register Safe House arrival
* Multiplayer layer
* Audio
* Special Infected (Smoker & Hunter)
* Use spawning zones rather than initiating all zombies at beginning
/**
 * Copyright swingpants ( http://wonderfl.net/user/swingpants )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/azMY
 */

/**
	 * ...
	 * @author Swingpants
         *
         * Left 2 Die - "Zombie Mayhem"
         * An exercise in cooperative play
         * 
         * Built for the Moock Checkmate Challenge - ran out of time - misjudged when deadline was
         * 
         * This is a single player version
         * 
         * Aim of game take your team to the safe house (top left corner)
         * Got to stay together to survive
         *
         * To Do:
         *
         * Register death
         * Register Safe House arrival
         * Multiplayer layer
         * Audio
         * Special Infected (Smoker & Hunter)
         * Use spawning zones rather than initiating all zombies at beginning
	 */
	

package 
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.display.Loader
	import flash.net.URLRequest
	import flash.display.Bitmap
        import flash.system.LoaderContext;

	
	
	[SWF(width = 480, height = 480, backgroundColor = 0x333333)] 
	
	public class Main extends Sprite 
	{
		private var _container:Sprite = new Sprite()
		private var _message_layer:Sprite=new Sprite()
		private var _controller:Controller
		private var _turn_timer:TurnTimer = new TurnTimer()
		private var _move_panel:MovePanel = new MovePanel()
		private var _loader:Loader 
		private const IMAGE_URLS:Array = ["http://www.swingpantsflash.com/images/terrain.jpg",
							"http://www.swingpantsflash.com/images/player1.png",
							"http://www.swingpantsflash.com/images/player2.png",
							"http://www.swingpantsflash.com/images/player3.png",
							"http://www.swingpantsflash.com/images/player4.png",
							"http://www.swingpantsflash.com/images/zombie.png"
										]
		private var _url_index:int = 0
		private var _terrain:Sprite = new Sprite()
		private var _canvas:Sprite = new Sprite()
		private var _p1_bmp:Bitmap 
		private var _p2_bmp:Bitmap
		private var _p3_bmp:Bitmap 
		private var _p4_bmp:Bitmap 
		private var _zombie_bmp:Bitmap 
		
		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			//this.graphics.beginFill(0xFF0000,0.6)
			//this.graphics.drawCircle(60, 60, 100)
			//this.graphics.endFill()
			loadNextImage()
		}
		
		private function loadNextImage():void
		{
			trace("[loadNextImage]")
                        var context:LoaderContext = new LoaderContext();
                        context.checkPolicyFile=true;
			_loader= new Loader();
			var req:URLRequest = new URLRequest(IMAGE_URLS[_url_index]);
			_loader.contentLoaderInfo.addEventListener( Event.COMPLETE, onLoadHandler );
			_loader.load(req,context);
		}
		
		private function onLoadHandler(event:Event):void 
		{
			trace("[onLoadHandler] - _url_index="+_url_index)

                        //switch throwing error "Expecting CaseLabel"!!?
                        if(_url_index==0)_terrain.addChild(_loader);
                        if(_url_index==1)_p1_bmp = Bitmap(_loader.content);
                        if(_url_index==2)_p2_bmp = Bitmap(_loader.content);
                        if(_url_index==3)_p3_bmp = Bitmap(_loader.content);
                        if(_url_index==4)_p4_bmp = Bitmap(_loader.content);
                        if(_url_index==5)_zombie_bmp = Bitmap(_loader.content);
			
			_url_index++
			if (_url_index < 6)
				{
					loadNextImage()
				}
				else
				{
					this.graphics.beginFill(0x00FF00,0.6)
					this.graphics.drawCircle(120, 120, 100)
					this.graphics.endFill()
					trace("CONTINUEINIT")
					continueInit()
				}
         }
		
		private function continueInit():void
		{
			var gb:GameBoard = new GameBoard(_terrain)
			addChild(gb)
			
			//Set up the controller
			_controller = new Controller(this.stage,gb,_message_layer,_move_panel,_turn_timer)
			//Add players (max 4)
			_controller.addPlayer(GameBoard.ROWS-4,GameBoard.COLS-1,_p1_bmp)
			_controller.addPlayer(GameBoard.ROWS-3,GameBoard.COLS-2,_p2_bmp)
			_controller.addPlayer(GameBoard.ROWS-2,GameBoard.COLS-3,_p3_bmp)
			_controller.addPlayer(GameBoard.ROWS-1,GameBoard.COLS-4,_p4_bmp)
			//Need to calc zombie patterns
			addZombieCluster(55, 55)
			addZombieCluster(54, 59)
			var spread:Number=4
			for (var i:int = 0; i < GameBoard.COLS; i += Math.round(spread))
				{
					for (var j:int = 0; j < GameBoard.ROWS; j += Math.round(spread))
						{
							if((i<GameBoard.COLS-10 || j<GameBoard.ROWS-10) && (i>10 || j>10))	addZombieCluster(i, j)
						}
					spread*=1.08
				}
			
			
			_turn_timer.x = 200
			_turn_timer.y = 300
			//
			
			gb.addChild(_message_layer)
			
			_move_panel.x = GameBoard.SCREENW*0.5;_move_panel.y=GameBoard.SCREENH*0.5
			
			_controller.update()

                        startGame()

		}

                public function startGame():void
                {
                    addChild(_turn_timer)
                    addChild(_move_panel)
                    _controller.startNextTurn()
                }
		
		private function addZombieCluster(posx:int, posy:int):void
		{
			var cluster:Array=[[1,0,0,1],[0,1,1,0],[0,1,1,0],[1,0,0,1]]
			for (var i:int = 0; i < 4; i++)
				{
					for (var j:int = 0; j < 4; j++)
						{
							if (cluster[i][j] == 1 && posx+j<GameBoard.COLS && posy+i<GameBoard.ROWS)
								{
									_controller.addZombie(posx+j,posy+i,duplicateImage(_zombie_bmp))
								}
						}
				}
		}
		
		private function duplicateImage(original:Bitmap):Bitmap 
		{
            var image:Bitmap = new Bitmap(original.bitmapData.clone());
            //image.x = size * numChildren;
            //addChild(image);
            return image;
        }
        
		
	}
}


import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.EventDispatcher
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.geom.Point
import caurina.transitions.Tweener
import flash.display.Stage
import flash.display.Bitmap

/***********************************************************************************************************************************************************
 * Controller - control of all views
 ***********************************************************************************************************************************************************/
class Controller
	{
		private const COLOURS:Array = [0xFF0000, 0xFF9900, 0x0000FF, 0xFFFF00]
		private const ZOMBIE_COLOUR:uint = 0x006600
		private const ACTIVE_RANGE:int = 10
		private const LONG_RANGE:int = 72
		private const ADJACENT:int=11
		private var _players:Array = []
		private var _distances:Array=[]
		private var _turn:Array=[{},{},{},{}]
		private var _zombies:Array = []
		private var _gameboard:GameBoard
		private var _message_layer:Sprite
		private var _move_panel:MovePanel
		private var _turn_timer:TurnTimer
		private var _stage:Stage
		private var _target_posn:Point=new Point()
		private var _bullets:Array = []
		
		private var _test_canvas:Sprite=new Sprite()
		
	public function Controller(stage:Stage,gameboard:GameBoard,message_layer:Sprite,move_panel:MovePanel,turn_timer:TurnTimer):void
		{
			_gameboard = gameboard
			_message_layer = message_layer
			_move_panel=move_panel
			_turn_timer = turn_timer
			_turn_timer.addEventListener(Event.COMPLETE, turnOverHandler)
			_stage = stage
			
			for (var i:int = 0; i < 4;i++){_distances[i]=[]}
		}
		//Add a player to the game board
		public function addPlayer(posx:int, posy:int, bmp:Bitmap):void
		{
			var p:Actor = new Actor(_message_layer, COLOURS[_players.length])
			bmp.x = 20; 
			bmp.y = -20
			bmp.width = 40; bmp.height = 40
			bmp.rotation=90
			p.addChild(bmp)
			p.health=20
			p.position=new Point(posx,posy)
			p.x = GameBoard.GRID_SIZE * posx+GameBoard.GRID_SIZE*0.5//_players.length
			p.y = GameBoard.GRID_SIZE * posy+GameBoard.GRID_SIZE*0.5//_players.length
			
			p.rotation=GameMaths.angleToPoint(p.position,new Point())
			
			var b:Sprite = new Sprite()
			b.graphics.beginFill(0xAAAAAA, 0.6)
			b.graphics.drawCircle(0, 0, 2)
			b.graphics.endFill()
			b.alpha=0
			//_bullets[_players.length] = b
			p.bullet=b
			_gameboard.addChild(b)
			_gameboard.addChild(p)
			p.name="player"+_players.length
			p.addMessage(p.name)
			_players.push(p)
			
			
		}
		
		//Add a zombie to the game board
		public function addZombie(posx:int,posy:int,bmp:Bitmap):void
		{
			var zombie:Actor = new Actor(_message_layer, ZOMBIE_COLOUR)
			bmp.x = 20; 
			bmp.y = -20
			bmp.width = 40; bmp.height = 40
			bmp.rotation = 90
			trace("bmp="+bmp)
			zombie.addChild(bmp)
			zombie.position=new Point(posx,posy)
			zombie.x = GameBoard.GRID_SIZE * posx+GameBoard.GRID_SIZE*0.5
			zombie.y = GameBoard.GRID_SIZE * posy + GameBoard.GRID_SIZE * 0.5
			zombie.name="z_"+_zombies.length
			_gameboard.addChild(zombie)
			_zombies.push(zombie)
			//zombie.addMessage("ZOMBIE_" + _zombies.length)
			//trace("NUm zombies so far:"+_zombies.length)
		}
		
		private function turnOverHandler(event:Event):void
		{trace("turnOverHandler")
			_move_panel.outOfTime()
			_turn[0] = _move_panel.option_selection
			calcPlayerDistances()
			calcBotMoves()
			turnOver()
		}
		private function calcPlayerDistances():void
		{
			var i:int; 
			var j:int
			var active_players:int=0
			for (i = 0; i < 3; i++)
				{
					for (j = i+1; j < 4; j++)
						{
							_distances[i][j] = GameMaths.distanceFromToSquared(_players[i].position, _players[j].position)
							_distances[j][i]=_distances[i][j]
						}
				}
			var tgtx:int
			var tgty:int
			for (i = 0; i < 4; i++)
				{
					if (_players[i].active)
						{
							active_players++
							var nearest:int = 9999
							var furthest:int= -1
							for (j = 0; j < 4; j++)
								{
									if (i != j)
										{
											if (_distances[i][j] < nearest) { _players[i].nearest = j; nearest = _distances[i][j] }
											if (_distances[i][j] > furthest) { _players[i].furthest = j; furthest = _distances[i][j] }
										}
								}
							tgtx += _players[i].position.x//Calc centre point for group - to be used by long range zombies to aim at.
							tgty += _players[i].position.y
						}
				}
			if(active_players>0)_target_posn=new Point(Math.round(tgtx/active_players),Math.round(tgty/active_players))
		}
		private function calcZombieMoves():void
		{
			var len:int = _zombies.length
			var posn:Point
			var nearest_inf:Object
			var aim_for :Point
			var ang:Number
			var adj:Boolean
			var diffx:int
			var diffy:int
			var turn:Object
			
			for (var i:int = 0; i < len; i++)
				{
				if (_zombies[i].active)
					{	
					posn = _zombies[i].position
					adj=false
					if (posn.x > _target_posn.x - ACTIVE_RANGE && posn.x < _target_posn.x + ACTIVE_RANGE
						&& posn.y > _target_posn.y - ACTIVE_RANGE && posn.y < _target_posn.y + ACTIVE_RANGE)
						{//ACTIVE
							nearest_inf = findNearestPlayer(posn)
							
							//if (nearest_inf.dist < ADJACENT)
							diffx = Math.abs(posn.x - _players[nearest_inf.nearest].position.x)
							diffy = Math.abs(posn.y - _players[nearest_inf.nearest].position.y)
							//trace("ZOMBIE "+i+" DISTANCE " + nearest_inf.dist+"  diffs:"+diffx+","+diffy)
							if(diffx<=1 && diffy<=1)
								{
									trace("ZOMBIE "+i+" ADJACENT SO FIGHT nearest:"+nearest_inf.nearest)
									aim_for = _players[nearest_inf.nearest].position
									_players[nearest_inf.nearest].health--//=i
									_players[nearest_inf.nearest].attackedBy=_zombies[i]
									_players[nearest_inf.nearest].doBloodSplatter(3, 0.2)
									adj=true
								}
								else
							if (nearest_inf > LONG_RANGE)
								{//LONG RANGE
									aim_for=_target_posn
								}
								else
								{//SHORT RANGE
									aim_for=_players[nearest_inf.nearest].position
								}
							if (adj)
								{
									//do attack
									trace("*****ADJACENT****")
								}

							ang = Math.round(GameMaths.angleToPoint(_zombies[i].position, aim_for ) / 45) +3//Div by 45 to make out of 8
							ang = ang<0?ang+8:ang>8?ang-8:ang
							turn =  { sel:adj?"FIGHT":"MOVE", dir:ang } 
							if (spaceEmptyOfCharacters(_zombies[i], turn)){_zombies[i].doTurn(turn)}
							else
								{
									turn.dir = turn.dir-1>=0?turn.dir-1:turn.dir+7
									if (spaceEmptyOfCharacters(_zombies[i], turn)) { _zombies[i].doTurn(turn) }
										else
											{
												turn.dir = turn.dir + 2 < 8?turn.dir + 2:turn.dir - 6
												if (spaceEmptyOfCharacters(_zombies[i], turn)) { _zombies[i].doTurn(turn) }
											}
								}
							//trace("####::"+_zombies[i].name+" posn="+posn.x+","+posn.y+"   grid coords:"+(posn.x + MovePanel.BUTTON_POSITIONS[ang].x)+","+(posn.y + MovePanel.BUTTON_POSITIONS[ang].y)+"  butpos:"+MovePanel.BUTTON_POSITIONS[ang].x+","+MovePanel.BUTTON_POSITIONS[ang].y)
						}
					_gameboard.positionGrid[posn.x ][posn.y ] = _zombies[i]
					//_zombies[i].addMessage("Z_" + i)
					}
				}
		}
		private function findNearestPlayer(posn:Point):Object
		{
			var dist:int
			var ndist:int=9999
			var nearest:int
			for (var i:int = 0; i < 4; i++)
				{
					if (_players[i].active)
						{
							dist = GameMaths.distanceFromToSquared(posn, _players[i].position)
							if (dist < ndist)
								{
									nearest = i
									ndist=dist
								}
						}
				}
			return { nearest:nearest, dist:dist }
		}
		private function calcBotMoves():void
		{
			//Randomish for now
			//Aim for top left. Avoid stepping onto other players.
			var dir_to_use:int = 0
			var selection:String="MOVE"
			var calcx:int
			var calcy:int
			var hit_obj:Object
			for (var i:int = 1; i < 4; i++)
				{
					dir_to_use = 0
					selection="MOVE"
					calcx = Math.abs(_players[i].position.x - _target_posn.x)
					calcy = Math.abs(_players[i].position.y - _target_posn.y)
					//trace(i + "::" + calcx + "," + calcy + "  SQD=" + (calcx * calcx + calcy * calcy) + " TGT POS=" + _target_posn)
					if (_players[i].attackedBy)
						{//Being attacked so shoot
							selection = "SHOOT"
							dir_to_use = dirToUse(_players[i].position, _players[i].attackedBy.position)
							_players[i].attackedBy=null
						}
						else
					if (calcx>2 || calcy>2)
						{//Too far from group
							dir_to_use = dirToUse(_players[i].position, _target_posn )
						}
						else
						{//Check if zombie in range for shot
							for (var k:int = 0; k < 8; k++)
								{
									hit_obj=shotWillHit(_players[i], { sel:"SHOOT", dir:k})
									if (hit_obj.hit && hit_obj.target.name.substr(0,1)=="z")
										{
											trace(k+"__ shoot at "+hit_obj.target.name)
											selection = "SHOOT"
											dir_to_use = k
											break;
										}
										else if (hit_obj.hit) { break;}
								}
						}
					trace("{calcBotMoves} i="+i+"  sel="+selection+"  dir="+dir_to_use+"   calcx/y="+calcx+","+calcy)
					_turn[i] = { sel:selection, dir:dir_to_use }
					if (selection == "MOVE")
						{
							if (!spaceEmptyOfCharacters(_players[i], _turn[i]))
								{
									_turn[i].dir = _turn[i].dir - 1 >= 0?_turn[i].dir - 1:_turn[i].dir + 7
									if (!spaceEmptyOfCharacters(_players[i], _turn[i]))
										{
											_turn[i].dir = _turn[i].dir + 2 < 8?_turn[i].dir + 2:_turn[i].dir - 6
										}
								}
						}
				}

		}
		private function dirToUse(player_posn:Point, target:Point):int
		{
			var dir_to_use:int = 0
			dir_to_use = Math.round(GameMaths.angleToPoint(player_posn, target) / 45) +3//Div by 45 to make out of 8
			dir_to_use = dir_to_use<0?dir_to_use+8:dir_to_use>8?dir_to_use-8:dir_to_use
			return dir_to_use
		}
		private function spaceEmptyOfCharacters(player:Actor, turn:Object):Boolean
		{
			if (turn.sel != "MOVE")
				{
					return true
				}
			else if(turn.dir>-1)
				{
					var posx:int = player.position.x + MovePanel.BUTTON_POSITIONS[turn.dir].x
					var posy:int = player.position.y + MovePanel.BUTTON_POSITIONS[turn.dir].y
					if (posx >= GameBoard.ROWS || posy >= GameBoard.COLS || posx < 0 || posy < 0)
						{
							return false
						}
					else
					if (_gameboard.positionGrid[posx][posy] && _gameboard.positionGrid[posx][posy].name!=player.name) 
						{
							if (posx == _gameboard.positionGrid[posx][posy].position.x && posy== _gameboard.positionGrid[posx][posy].position.y)
								{
									//trace(player.name+" AT "+player.position+" CANT GO HERE "+posx+","+posy+" AS OCCUPIED BY "+_gameboard.positionGrid[posx][posy].name+"  AT  "+_gameboard.positionGrid[posx][posy].position)
									return false	
								}
								else
								{
									//trace("//FALSE READING// "+player.name+" AT "+player.position+" CANT GO HERE "+posx+","+posy+" AS OCCUPIED BY "+_gameboard.positionGrid[posx][posy].name+"  AT  "+_gameboard.positionGrid[posx][posy].position)
									return true
								}
							
						}
						else return true
				}
			else return false
		}
		private function shotWillHit(player:Actor,turn:Object):Object
		{
			var obj:Object = { }
			var posx:int
			var posy:int
			var dir:Object = MovePanel.BUTTON_POSITIONS[turn.dir]
			for (var i:int = 0; i < 6; i++)
				{
					posx = player.position.x + dir.x * (i + 1)
					posy = player.position.y + dir.y * (i + 1)
					//trace("bullet path i="+i+"  pos="+posx+","+posy)
					if (posx >= 0 && posy >= 0 && posx < GameBoard.COLS && posy < GameBoard.ROWS)
						{
							if (_gameboard.positionGrid[posx][posy])
								{
									if (_gameboard.positionGrid[posx][posy].active)
										{
											obj.hit=true
											obj.target = _gameboard.positionGrid[posx][posy]
											obj.position = obj.target.position
											obj.dist = i
											break;
										}
								}
						}
				}
				if (!obj.hit)
					{
						obj.hit = false
						obj.position = { x:player.position.x + dir.x * 6, y:player.position.y + dir.y * 6 }
						obj.dist = 6
					}
			return obj
		}
		
		public function turnOver():void
		{
			//DO MOVE
			var i:int
			for (i = 0; i < 4; i++)
				{
				if (_players[i].active)
					{
					if (_turn[i].sel == "MOVE")
						{
							_gameboard.positionGrid[_players[i].position.x][_players[i].position.y]=null//Remove player from board
							if (spaceEmptyOfCharacters(_players[i], _turn[i]))	_players[i].doTurn(_turn[i])//Do turn
							_gameboard.positionGrid[_players[i].position.x][_players[i].position.y] = _players[i]//Put player back on board
						}
						else
					if (_turn[i].sel == "SHOOT" && _turn[i].dir>-1)
						{
							var shot:Object = shotWillHit(_players[i], _turn[i])
							if (shot.hit)
								{
									trace("-------------BANG!-------------" + shot.position)
									shot.target.health--
									shot.target.doBloodSplatter(_turn[i].dir, shot.dist * 0.2)
									if (!shot.target.active)	
										{
											_gameboard.positionGrid[shot.position.x][shot.position.y]=null
											Tweener.addTween(shot.target,{alpha:0,delay:shot.dist * 0.2,time:1.5})
										}
								}
								else
								{
									trace("-------------BANG! MISSED-------------"+shot.position)
								}
							_players[i].bullet.alpha = 0.6
							_players[i].bullet.x = _players[i].x
							_players[i].bullet.y = _players[i].y
							Tweener.addTween(_players[i].bullet, { x:(shot.position.x+0.5) * GameBoard.GRID_SIZE, y:(shot.position.y+0.5) * GameBoard.GRID_SIZE, time:shot.dist * 0.2, transition:"Linear" } )
							Tweener.addTween(_players[i].bullet, { alpha:0, delay:shot.dist * 0.2, time:0.1 } )
							_players[i].doTurn(_turn[i])
						}
					}
				}
			_gameboard.clearPositionGrid()
			for (i = 0; i < 4; i++) { if (_players[i].active)_gameboard.positionGrid[_players[i].position.x][_players[i].position.y] = _players[i]  }
			
			calcZombieMoves()
			
			//PLAYER HEALTH CHECK
			for (i = 0; i < 4; i++) 
				{ 
					if (!_players[i].active && _players[i].parent)
						{
							_players[i].parent.removeChild(_players[i])
							_gameboard.positionGrid[_players[i].position.x][_players[i].position.y]=null
						}
				}
			
			if (_turn_timer.parent)_turn_timer.parent.removeChild(_turn_timer)
			Tweener.addTween(_stage,{time:3,onComplete:update})
			Tweener.addTween(_stage,{time:5,onComplete:startNextTurn})
		}
		public function startNextTurn():void
		{
			_turn_timer.startTimer()
			_move_panel.startPanel()
			_stage.addChild(_turn_timer)
		}
		public function update():void
		{
			_gameboard.centrePlayerPiece(_players[0])
		}
	}
	
	
	
/***********************************************************************************************************************************************************
 * Actor - Class to contain actor view
 ***********************************************************************************************************************************************************/
class Actor extends Sprite
	{
		private var _holder:Sprite = new Sprite()
		private var _bubble:Sprite = new Sprite()
		private var _bubble_bg:Sprite = new Sprite()
		private var _bullet:Sprite
		private var _tf:TextField = new TextField()
		private var _position:Point = new Point()
		private var _nearest:int
		private var _furthest:int
		private var _close_fighting:int = -1
		private var _health:int = 1
		private var _active:Boolean = true
		private var _blood_splatter:Array = []
		private var _attacked_by:Actor
		
		public function Actor(message_layer:Sprite, colour:uint=0xFFFF00):void
		{
			var gsize:int=GameBoard.GRID_SIZE
			//_holder.graphics.lineStyle(6, colour)
			//_holder.graphics.drawCircle(gsize * 0.5, gsize * 0.5, gsize * 0.3)
			//_holder.graphics.drawRoundRect(gsize * 0.4, gsize * 0.1, gsize * 0.2, gsize * 0.8, 5, 5)
			//_holder.x = _holder.y = -gsize * 0.5
			//addChild(_holder)
			message_layer.addChild(_bubble)
			//Set up textfield
			_tf.textColor=0x000000
			_tf.selectable=false
			_tf.x = gsize+3
			_tf.y = -gsize * 0.2
			
			_bubble.addChild(_bubble_bg)//Add background container for bubble
		}
		//Add a message to speech bubble
		public function addMessage(msg:String):void
		{
			var gsize:int = GameBoard.GRID_SIZE
			_bubble.x = this.x-gsize*0.5
			_bubble.y = this.y-gsize*0.5
			trace("___"+_bubble.x+","+_bubble.y)
			
			_bubble.addChild(_tf)
			_tf.text = msg//Add message
			Tweener.removeTweens(_bubble) //1st remove current tweens on this bubble
			Tweener.addTween(_bubble, { alpha:1, time:0.5 } ) //Tween on
			Tweener.addTween(_bubble, { alpha:0, delay:3, time:0.5, onComplete:removeTextFromBubble } )//Tween off after delay
			//Draw bubble to correct size
			_bubble_bg.graphics.clear()
			_bubble_bg.graphics.lineStyle(2, 0xFFFFFF)
			_bubble_bg.graphics.beginFill(0xDDDDDD,0.7)
			_bubble_bg.graphics.drawRoundRectComplex(gsize,-gsize*0.2,_tf.textWidth+10,gsize*0.5,10,10,1,10)
		}
		//Needed to get rid of text - can't be bothered dealing with embedding text, etc at this stage.
		private function removeTextFromBubble():void { _bubble.removeChild(_tf); }
		
		public function get active():Boolean { return _active }
		
		public function set health(val:int):void { _health = val;_active=_health>0?true:false }
		public function get health():int { return _health }
		
		public function set bullet(b:Sprite):void { _bullet = b }
		public function get bullet():Sprite { return _bullet }
		
		public function set position(pt:Point):void { _position = pt }
		public function get position():Point { return _position }
		
		public function set furthest(val:int):void { _furthest = val}
		public function get furthest():int { return _furthest }
		
		public function set nearest(val:int):void { _nearest = val}
		public function get nearest():int { return _nearest }
		
		public function set fighting(val:int):void { _close_fighting = val}
		public function get fighting():int { return _close_fighting }
		
		public function set attackedBy(attacker:Actor):void { _attacked_by = attacker}
		public function get attackedBy():Actor { return _attacked_by }
		
		public function doTurn(turnObj:Object):void
		{
			//trace("[Actor] - doTurn turnObj.sel="+turnObj.sel+"  dir="+turnObj.dir)
			if (turnObj.sel == "MOVE" && turnObj.dir >= 0) { moveActor(turnObj.dir) }
				else if (turnObj.sel == "FIGHT") fightActor()
				else if(turnObj.sel=="SHOOT") rotateActor(MovePanel.BUTTON_POSITIONS[turnObj.dir].rot-90)
		}
		public function rotateActor(rotate:Number):void
		{
			Tweener.addTween(this,{rotation:rotate, time:0.3})
		}
		private function fightActor():void
		{
			trace("FIGHT"+this.rotation)
			var orig_rot:Number=this.rotation
			Tweener.addTween(this, { rotation:orig_rot - 60, time:0.2 } )
			Tweener.addTween(this, { rotation:orig_rot, delay:0.2,time:2, transition:"easeOutElastic"})
		}
		public function moveActor(dir_index:int):void
		{
			if (_close_fighting == -1)
				{
					var move_obj:Object = MovePanel.BUTTON_POSITIONS[dir_index]
					rotateActor(move_obj.rot - 90)
					Tweener.addTween(this, { x:this.x + move_obj.x * GameBoard.GRID_SIZE, y:this.y + move_obj.y * GameBoard.GRID_SIZE, delay:1, time:3 } )
					_position.x += move_obj.x
					_position.y += move_obj.y
				}
		}
		public function doBloodSplatter(hit_from:int, delay:Number=0):void
		{
			var splatter_dir:int = hit_from - 4 < 0?hit_from + 4:hit_from - 4//Opposite direction for splatter
			var dir_obj:Object=MovePanel.BUTTON_POSITIONS[splatter_dir]
			if (!_blood_splatter[splatter_dir]) _blood_splatter[splatter_dir] = new Sprite()
			//_blood_splatter[splatter_dir].x = dir_obj.x * GameBoard.GRID_SIZE * 0.3
			//_blood_splatter[splatter_dir].y = dir_obj.y * GameBoard.GRID_SIZE * 0.3
			_blood_splatter[splatter_dir].alpha=0
			addChild(_blood_splatter[splatter_dir])
			bloodSplatter(_blood_splatter[splatter_dir], 20)
			Tweener.addTween(_blood_splatter[splatter_dir],{alpha:1,delay:delay})
			Tweener.addTween(_blood_splatter[splatter_dir],{alpha:0,delay:delay,time:1.5,transition:"Linear"})
		}
		private function bloodSplatter(container:Sprite,radius:Number):void
		{
			var diameter:Number=radius*2
			container.graphics.clear()
			container.graphics.beginFill(0xFF0000,0.8)
			container.graphics.drawRoundRectComplex(-radius, -radius, diameter, diameter, radius-diameter*Math.random(), radius*2-diameter*2*Math.random(), radius-diameter*Math.random(), radius*2-diameter*Math.random())
			container.graphics.endFill()
			container.rotation = Math.random() * 360
			container.width = radius + radius * Math.random()
			container.height = radius+radius*Math.random()
		}
	}
/***********************************************************************************************************************************************************
 * GameBoard - class to contain gameboard view
 ***********************************************************************************************************************************************************/
class GameBoard extends Sprite
	{
		private var _holder:Sprite = new Sprite()
		public static const GRID_SIZE:int = 40
		public static const COLS:int = 32
		public static const ROWS:int = 32
		
		public static const SCREENW:int = 480
		public static const SCREENH:int = 480
		
		private var _pos_grid:Array
		private var _blank_grid:Array
		
		public function GameBoard(terrain:Sprite):void
		{
			addChild(terrain)
			_holder.graphics.lineStyle(4, 0x000000)
			_holder.graphics.beginFill(0x666666,0.5)
			_holder.graphics.drawRect(0, 0, ROWS * GRID_SIZE, COLS * GRID_SIZE)
			_holder.graphics.endFill()
			for (var i:int = 0; i < ROWS; i++)
				{
					for (var j:int = 0; j < COLS; j++)
					{
						_holder.graphics.lineStyle(1, 0x333333)
						_holder.graphics.drawRect(i*GRID_SIZE,j*GRID_SIZE, GRID_SIZE,GRID_SIZE)
					}
				}
			addChild(_holder)
			initPositionGrid()
		}
		private function initPositionGrid():void
		{
			var r:Array = []
			for (var i:int = 0; i < COLS; i++)
				{
					r[i]=new Array(ROWS)
				}
			_blank_grid = r
			clearPositionGrid()
		}
		public function clearPositionGrid():void { _pos_grid = _blank_grid.concat() }
		public function get positionGrid():Array { return _pos_grid }

		//Move player piece on game board to centre of screen
		public function centrePlayerPiece(p:Actor):void
		{
			Tweener.addTween(this,{x:SCREENW * 0.5 - p.x+GRID_SIZE*0.5, y:SCREENH * 0.5 - p.y+GRID_SIZE*0.5,time:1})
		}
	}
/***********************************************************************************************************************************************************
 * TurnTimer - class to run & display timer
 ***********************************************************************************************************************************************************/
	class TurnTimer extends Sprite
	{
		private var _tf:TextField = new TextField()
		private var _colour_block:Sprite=new Sprite()
		public function TurnTimer():void
		{
			addChild(_colour_block)
			_colour_block.graphics.beginFill(0xFF0000)
			_colour_block.graphics.drawRect(2, 1, 100, 6)
			addChild(_colour_block)
			
			_tf.x = 5
			_tf.y = 8
			_tf.textColor=0xEEEEEE
			addChild(_tf)
			addMessage("ENTER TURN")
			
			var brder:Sprite = new Sprite()
			addChild(brder)
			brder.graphics.lineStyle(2, 0x003300)
			brder.graphics.drawRoundRect(0, 0, 102, 8, 5, 5)
			
			//startTimer()
		}
		public function addMessage(msg:String):void
		{
			_tf.text=msg
		}
		public function startTimer():void
		{
			Tweener.removeTweens(_colour_block)
			Tweener.addTween(_colour_block, { width:1, time:5, transition:"Linear", onComplete:timesUp } )
		}
		private function timesUp():void
		{
			_colour_block.width = 100
			dispatchEvent(new Event(Event.COMPLETE))
			//startTimer()
		}
	}
/***********************************************************************************************************************************************************
 * MovePanel - panel containing movement buttons
 ***********************************************************************************************************************************************************/
	class MovePanel extends Sprite
	{
		private var _button_array:Array = []
		public static const BUTTON_POSITIONS:Array = [ { x:-1, y:-1, rot: -45 }, { x:0, y:-1, rot:0 }, { x:1, y:-1, rot:45 }, { x:1, y:0, rot:90 }, { x:1, y:1, rot:135 }, { x:0, y:1, rot:180 }, { x:-1, y:1, rot: -135 }, { x:-1, y:0, rot: -90 } ]
		private var _directions:Sprite = new Sprite()
		private var _buttons:Sprite = new Sprite()
		private var _selection:Object={}
		public function MovePanel():void
		{
			var unit:Number = GameBoard.GRID_SIZE * 0.5
			
			var b1:Button = new Button("MOVE", "rectangle")
			b1.x=-5
			_buttons.addChild(b1)
			var b2:Button = new Button("SHOOT", "rectangle")
			b2.x=-5
			b2.y = 25
			_buttons.addChild(b2)
			b1.addEventListener(MouseEvent.CLICK, buttonClickedHandler)
			b2.addEventListener(MouseEvent.CLICK,buttonClickedHandler)
			addChild(_buttons)
			for (var i:int = 0; i < 8; i++)
				{
					var b:Button = new Button("b" + i, "triangle",8)
					b.setPosition(BUTTON_POSITIONS[i].x * unit, BUTTON_POSITIONS[i].y * unit, BUTTON_POSITIONS[i].rot)
					b.extra=i
					_button_array.push(b)
					_directions.addChild(b)
					b.addEventListener(MouseEvent.CLICK, directionClickedHandler)
				}
			_directions.x = _directions.y=unit
		}
		public function outOfTime():void
		{
			if (_buttons.parent) removeChild(_buttons)
			if(_directions.parent) removeChild(_directions)
		}
		public function startPanel():void
		{
			_selection = {dir:-1 }
			addChild(_buttons)
		}
		private function buttonClickedHandler(event:MouseEvent):void
		{
			_selection.sel = event.target.name
			trace(event.target.name)
			removeChild(_buttons)
			addChild(_directions)
		}
		private function directionClickedHandler(event:MouseEvent):void
		{
			trace("directionClickedHandler dir="+event.target.extra)
			_selection.dir = event.target.extra
			removeChild(_directions)
		}
		public function timeStarted():void { _selection = { }}
		public function get option_selection():Object{return _selection}
	}
/***********************************************************************************************************************************************************
 * Button - generic button class - triangle or rectangle
 ***********************************************************************************************************************************************************/	
	class Button extends Sprite
	{
		private var _alpha:Number = 0.5
		private var _extra:Object={}
		public function Button(id:String, type:String, size:int=6,bg_colour:uint=0x0000FF,br_colour:uint=0x000099):void
		{
			this.name=id
			this.graphics.beginFill(bg_colour, 1)
			this.graphics.lineStyle(2,br_colour)
			switch(type)
				{
					case "triangle":
						this.graphics.moveTo(0, -size)
						this.graphics.lineTo(size, size)
						this.graphics.lineTo( -size, size)
						this.graphics.lineTo(0, -size)
						
						break;
					case "rectangle":
						this.graphics.drawRoundRect(0, 0, 50, 20, 5, 5)
						var tf:TextField = new TextField()
						tf.x = 2; tf.y = 2;
						tf.textColor=0xFFFFFF
						tf.text = id
						tf.selectable = false
						tf.mouseEnabled=false
						addChild(tf)
						_alpha=0.8
						break;
				}
			this.graphics.endFill()
			this.addEventListener(MouseEvent.MOUSE_OVER, mouseOverHandler)
			this.addEventListener(MouseEvent.MOUSE_OUT, mouseOutHandler)
			//this.addEventListener(MouseEvent.CLICK, mouseClickHandler)
			this.useHandCursor = true
			this.buttonMode = true
			this.alpha=_alpha
		}
		private function mouseOverHandler(event:MouseEvent):void { this.alpha = 1 }
		private function mouseOutHandler(event:MouseEvent):void { this.alpha = _alpha }
		private function mouseClickHandler(event:MouseEvent):void { dispatchEvent(event) }
		
		public function setPosition(posx:Number, posy:Number, rot:Number=9999):void	
		{
			this.x = posx
			this.y = posy
			if(rot!=9999)this.rotation=rot
		}
		public function set extra(obj:Object):void { _extra = obj }
		public function get extra():Object { return _extra }
	}


/*	
	class CommsInterface extends EventDispatcher
	{
		private var _player_moves:Array=[]
		public function CommsInterface():void
		{
			
		}
		public function prepareToReceiveMoves():void
		{
			_player_moves=[]
		}
		//Player moves convert to...  F is fire, M is move. 0-7 are directions
		public function receivePlayerMove(player_num:int,obj:Object):void
		{
			var str:String="N"
			if (obj.sel)
				{
					if (obj.sel == "MOVE") str = "M"
						else str = "F"
					if (obj.dir)
						{
							str+=String(obj.dir+1)
						}
				}
			_player_moves[player_num]=str
		}
	}
*/	
	

	class GameMaths extends EventDispatcher
	{
		public function GameMaths():void {}
		
		public static function angleToPoint(from:Point, to:Point):Number
		{
			var dx:Number = to.x - from.x
			var dy:Number = to.y - from.y
			return Math.atan2(dy,dx) *57.29577951308232   //  180/Math.PI=57.29577951308232
		}
		public static function distanceFromToSquared(from:Point, to:Point):Number
		{
			var dx:Number = from.x - to.x
			var dy:Number = from.y - to.y
			return dx*dx+dy*dy
		}

	}