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

itatsu's Bots 0.20 + bot types

itatsu's Bots 0.20 personalities variant
Original work by itatsu
Feb.2.2009
Hold down left mousebutton and drag to scroll
Left click to select a bot
Press Space to pause/resume
Press R to free the viewpoint
0.15よりずいぶん軽くなりました。
次の目標:AIや画面の改良など
Botsのアップグレード機能を追加すればどうかな...
// itatsu's Bots 0.20 personalities variant
// Original work by itatsu
// Feb.2.2009
//
// Hold down left mousebutton and drag to scroll
// Left click to select a bot
// Press Space to pause/resume
// Press R to free the viewpoint
//
// 0.15よりずいぶん軽くなりました。
// 次の目標:AIや画面の改良など
// Botsのアップグレード機能を追加すればどうかな...
// 

package {
	import flash.display.*;
	import flash.events.*;

	[SWF(width="465", height="465", backgroundColor="30", frameRate="60")]
	public class MyBots extends Sprite {
		public function MyBots() {
			global = this;
			stage.quality = StageQuality.HIGH;

			Initialize();

			global.addEventListener(Event.ENTER_FRAME, Update);
			stage.addEventListener(MouseEvent.CLICK, MouseClick);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, MouseDown);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, MouseMove);
			stage.addEventListener(MouseEvent.MOUSE_UP, MouseUp);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyDown);
		}
	}
}

import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
import flash.filters.*;

// Global object
var global:Sprite;
// Main text field
var tField:TextField = new TextField;
// Sub text field
var stField:TextField = new TextField;
// Frame ticks
var ticks:uint;

// Bots vector
var bots:Vector.<Bot> = new Vector.<Bot>();
var botsactive:uint = 0;
// Bullets vector
var bullets:Vector.<Bullet> = new Vector.<Bullet>();

// Viewpoint
var viewpoint:Point = new Point(0, 0); 		// Top left of FOV
var tempviewpoint:Point = new Point(0, 0); 	// Top left of FOV
var curviewpoint:Point = new Point(0, 0); 	// Top left of FOV
// Mousedownpoint
var mousedownpoint:Point = new Point(0, 0);

// Selected bot
var selectedbot:Bot;

// Paused?
var paused:Boolean = false;

// Bot count from start
var botcount:uint = 0;

// Map size
const mapsizex:uint = 1000;
const mapsizey:uint = 1000;

// Performance related
const maxbots:uint = 15;

// AI types:
// 0 - normal (more hate towards more kills, distance falloff)
// 1 - god (more hate towards more kills, no distance falloff)
// 2 - sniper (attacks targets with the most distance)
// 3 - racist (hates attackers of racists, hates other racists less)
// 4 - hater (normal, but hates three times as much)
// 5 - relentless (picked target gets 60 seconds of hate)
// Bots type array (Blame me for all of this)
var bottotalprob:uint;
var bottypes:Array = [
   //               Name     , maxhp, type, speed, turn, shotspeed, bdmg, bspeed, blife, bdev, shield, regen, prob, color
   Bot.StatInstance("God"    ,   750,    1,   2.0,  2.0,         5, 24.0,    5.0,   75,  12.0,    5.0,  0.30,    2, 0xffff80),
   Bot.StatInstance("Demigod",   500,    1,   2.0,  2.0,         6, 22.0,    4.8,   72,  15.0,    4.0,  0.25,    5, 0xeeee50),
   Bot.StatInstance("Jerk"   ,   200,    4,   1.3,  1.2,         8, 15.0,    4.2,   64,  18.0,    2.0,  0.12,   50, 0x80ffff),
   Bot.StatInstance("Speeder",    80,    0,   2.5,  2.0,         7, 15.0,    4.5,   40,  15.0,    0.0,  0.22,  100, 0xff80ff),
   Bot.StatInstance("Tank"   ,   400,    0,   0.4,  0.7,         8, 13.0,    4.0,   60,  20.0,    5.0,  0.15,  100, 0x80ff80),
   Bot.StatInstance("Sniper" ,   150,    2,   0.9,  1.2,        80, 60.0,   13.0,  240,   4.0,    1.0,  0.10,   60, 0x8080ff),
   Bot.StatInstance("Racist" ,   180,    3,   1.0,  1.2,         3,  8.0,    5.0,   18,  40.0,    0.0,  0.16,  200, 0xffffff),
   Bot.StatInstance("Rager"  ,   300,    5,   1.1,  1.0,         9, 11.0,    3.8,   45,  18.0,    2.0,  0.12,   75, 0xff8080),
   Bot.StatInstance("Normal" ,   100,    0,   1.0,  1.0,         8, 15.0,    4.0,   60,  20.0,    1.0,  0.10, 1000, 0x808080),

   ];

var botnames:Array = [ 
   ["Zeus", "Poseidon", "Hades", "Hestia", "Ares", "Athena", "Apollo", "Aphrodite", "Hermes", "Artemis", "Hephaestus"],
   ["Achilles", "Amphion", "Britomartis", "Cycnus", "Gilgamesh", "Helen", "Hercules", "Lacedaemon", "Orion", "Perseus", "Sarpedon", "Tityas", "Zetes", "Zethus"],
   ["You", "Me", "Them", "Us", "Her", "Him", "They", "We", "I", "It" ],
   ["Ascari", "Mustang", "Viper", "Corvette", "Veyron", "Europa", "Spyder", "RX-8", "Aurian", "Impreza"],
   ["M1A1", "Tiger", "Panzer", "T72", "T62", "M4A1", "Challenger 2", "M60", "T34"],
   ["30-06", "308", "50", "9mm", "44 Magnum", "357", "22", "12 Gauge", "410", "38 Special"],
   ["Billy Bob", "Billy Joe", "Joey Bob"],
   ["Hate", "Death", "Pain", "Murderer", "Killer", "Revenge", "Vengeance", "Hunter", "Predator"],
   ["Normal", "Conformist", "Clone", "Generic", "Common"] 
   ];

// Bullets parameters
const CollisionDistance:Number = 85.0;
const sCollisionDistance:Number = Math.sqrt(85.0);
const SafeDistance:Number = 12.0;


// Initialize
function Initialize():void {
	var tFormat:TextFormat = new TextFormat;
	tFormat.font = "Arial";
	tFormat.bold = false;
	tFormat.color = 0xffffff;
	tFormat.size = 11;
	tFormat.align = TextFormatAlign.LEFT;

	tField.defaultTextFormat = tFormat;
	tField.selectable = false;
	tField.x = 5;
	tField.y = 428;
	tField.width = 460;
	tField.antiAliasType = AntiAliasType.ADVANCED;
	
	stField.defaultTextFormat = tFormat;
	stField.selectable = false;
	stField.x = 370;
	stField.y = 105;
	stField.width = 95;
	stField.height = 360;
	stField.antiAliasType = AntiAliasType.ADVANCED;

        // calc total prob for bot generation
        bottotalprob = 0;
        for each (var bot:Bot in bottypes)
            bottotalprob += bot.prob;
}

// Main Update
function Update(evt:Event):void {
	while (global.numChildren > 0) {
		global.removeChildAt(0);
	}
	if (!paused) {
		ticks++;
		
		UpdateAction();
		UpdateWorld();
	}
	Draw();
}

// Update bots action
function UpdateAction():void {
	UpdateBotsAI();
}

// Update world status
function UpdateWorld():void {
	// Generate bots
	// Cheat
	if (ticks == 1) {
                GenBotIndex(0); // God
	}
	if (ticks % 10 == 0) {
            if (botsactive < maxbots)
                GenBot();
        }

	// 
	UpdateBots();
	UpdateBullets();
	CollisionCheckes();
	
	// Rubbish collecting
	CollectBots();
	CollectBullets();
}

// Draw
function Draw():void {
	UpdateViewpoint();
	DrawMap();
	DrawBots();
	DrawBullets();
	DrawMinimap();
	DrawSelectedBot();
	DrawBotStatus();
	DrawTextField();
	DrawPaused();
}

// Update bots decision
function UpdateBotsAI():void {
	var len:uint = bots.length;
    	for (var i:uint = 0; i < len; i++) {
            if (!bots[i].exist)
                continue;

            var aitype:uint = bots[i].type;

            if (bots[i].target == null || bots[i].targethate <= 0)
            {
                // find something to hate
	        for (var j:uint = 0; j < len; j++) {
                        if (i == j || !bots[j].exist)
                            continue;

                        var dist:Number = Distance(bots[j].pos, bots[i].pos, 10000);
                        var hate:uint = 300;
                        
                        // add hate for kills (except sniper/racist)
                        if (aitype != 2 && aitype != 3)
                            hate += 90 * bots[j].kills
                        
                        // modify distance for gods and snipers
                        if (aitype == 1)
                            dist = 0; // Gods see all
                        else if (aitype == 2)
                            dist = 40000 - dist; // invert distance

                        if (hate < (dist / 200))
                            hate = 1;
                        else
                            hate -= dist / 200;

                        // racist logic
                        if (aitype == 3) {
                            if (bots[j].type == 3)
                                hate /= 5;
                            else if (bots[j].target != null && bots[j].target != bots[i] && bots[j].type == 3)
                                hate *= 2;
                        }

                        if (hate > bots[i].targethate) {
                            bots[i].target = bots[j];
                            bots[i].targethate = hate;
                        }
		}

                // found something so do per extra ai stuff?
                if (bots[i].target != null) {
                        if (aitype == 2 && bots[i].targethate > 600)
                            bots[i].targethate = 600;
                        if (aitype == 4)
                            bots[i].targethate *= 3;
                        else if (aitype == 5)
                            bots[i].targethate = 3600;
                }
            }
            else
            {   
                var targ:Bot = bots[i].target;
                if (targ.exist)
                {
                    bots[i].FaceToPosition(targ.pos);
		    bots[i].dir = (bots[i].dir + 360) % 360;
                    bots[i].targethate--;
                }
                else
                    bots[i].targethate = 0;
            }
	}
}

// Update bots
function UpdateBots():void {
	var len:uint = bots.length;
	for (var i:uint = 0; i < len; i++) {
                if (!bots[i].exist)
                    continue;

		// regen
		bots[i].hp += bots[i].regen;
		if (bots[i].hp > bots[i].maxhp) bots[i].hp = bots[i].maxhp;
		// move
		MoveBot(i);
		// shoot
		var genpos:Point = new Point;
		genpos.x = bots[i].pos.x;
		genpos.y = bots[i].pos.y;
		genpos.x += Math.sin(bots[i].dir / 180 * Math.PI) * SafeDistance;
		genpos.y -= Math.cos(bots[i].dir / 180 * Math.PI) * SafeDistance;
		if (ticks % bots[i].shotspeed == 0) {
			GenBullet(bots[i], genpos,
			bots[i].dir + Math.random() * bots[i].bdev * 2 - bots[i].bdev, 	// 散布界
			bots[i].bdamage, bots[i].bspeed, bots[i].blifespan
			); 
		}
	}
}
// Move specific bot
function MoveBot(no:uint):void {	
	// Do move
	bots[no].pos.x += Math.sin(bots[no].dir / 180 * Math.PI) * bots[no].speed;
	bots[no].pos.y -= Math.cos(bots[no].dir / 180 * Math.PI) * bots[no].speed;
	
	// Loop
	if (bots[no].pos.x < 0) bots[no].pos.x += mapsizex
	if (bots[no].pos.x > mapsizex) bots[no].pos.x -= mapsizex;
	if (bots[no].pos.y < 0) bots[no].pos.y += mapsizey;
	if (bots[no].pos.y > mapsizey) bots[no].pos.y -= mapsizey;
}

// Update bullets
function UpdateBullets():void {
	var len:uint = bullets.length;
	for (var i:uint = 0; i < len; i++) {
		// move
		MoveBullet(i);
		// life
		bullets[i].lifetime++;
		if (bullets[i].lifetime >= bullets[i].lifespan) {
			bullets[i].exist = false;
		}
	}
}
// Move specific bullet
function MoveBullet(no:uint):void {
	// Do move
	bullets[no].pos.x += Math.sin(bullets[no].dir / 180 * Math.PI) * bullets[no].speed;
	bullets[no].pos.y -= Math.cos(bullets[no].dir / 180 * Math.PI) * bullets[no].speed;
	
	// Loop
	if (bullets[no].pos.x < 0) bullets[no].pos.x += mapsizex;
	if (bullets[no].pos.x > mapsizex) bullets[no].pos.x -= mapsizex;
	if (bullets[no].pos.y < 0) bullets[no].pos.y += mapsizey;
	if (bullets[no].pos.y > mapsizey) bullets[no].pos.y -= mapsizey;
}

// Collision detect
function CollisionCheckes():void {
	var len:uint = bullets.length;
	for (var i:uint = 0; i < len; i++) {
		var target:int = CollisionCheck(i);
		if (target > -1) {
			var dam:Number = bullets[i].damage - bots[target].shield;
			if (dam < 0) dam = 0;
			bots[target].hp -= dam;
                        bots[target].AddHate(bullets[i].bot, dam * 4);
			bullets[i].exist = false;
			if (bots[target].hp <= 0) {
				bots[target].exist = false;
                                botsactive--;
				bullets[i].bot.kills++;
				bullets[i].bot.cash += 50;
			}
		}
	}
}
function CollisionCheck(no:uint):int {
	var len:uint = bots.length;
	for (var i:uint = 0; i < len; i++) {
                if (!bots[i].exist)
                    continue;

		var dist:Number = Distance(bullets[no].pos, bots[i].pos, sCollisionDistance);
		if (dist <= CollisionDistance && dist > 0) {
			return i;
		}
	}
	return -1;
}

// Rubbish collecting
function CollectBots():void {
        /*
	var _bots:Vector.<Bot> = new Vector.<Bot>();
	var len:uint = bots.length;
	for (var i:uint = 0; i < len; i++) {
		if (bots[i].exist) {
			_bots.push(bots[i]);
		}
		else bots[i] = null;
	}
	bots = _bots;
        */
}
function CollectBullets():void {
	var _bullets:Vector.<Bullet> = new Vector.<Bullet>();
	var len:uint = bullets.length;
	for (var i:uint = 0; i < len; i++) {
		if (bullets[i].exist) {
			_bullets.push(bullets[i]);
		}
		else bullets[i] = null;
	}
	bullets = _bullets;
}

function GenBotIndex(idx:uint):void {
    var len:uint = bots.length;
    var newbot:Bot = bottypes[idx].Clone(new Point(Math.random() * mapsizex, Math.random() * mapsizey),
        Math.random() * 360,
        true);
    var nameidx:uint = Math.random() * botnames[idx].length;
    var newname:String = botnames[idx][nameidx];

    botcount++;
    newbot.name = newname + "-" + botcount;

    botsactive++;
    for (var i:uint = 0; i < len; i++) {
            if (!bots[i].exist) {
                bots[i] = newbot;
                return;
            }
    }

    // if we made it this far just add it to the vector
    bots.push(newbot);
}

function GenBot():void {
    var p:uint = Math.random() * bottotalprob;
    var idx:uint = 0;

    while (p >= bottypes[idx].prob) {
        p -= bottypes[idx].prob;
        idx++;
    }

    GenBotIndex(idx);
}

function GenBullet(bot:Bot, pos:Point, dir:Number, damage:Number, speed:Number, lifespan:uint):void {				
	bullets.push(new Bullet(bot, pos, dir, damage, speed, lifespan));
}


function NearestBot(no:uint):uint {
	var nearestno:int = -1;
	var nearestdis:Number;
	var len:uint = bots.length;
	for (var i:uint = 0; i < len; i++) {
                if (!bots[i].exist)
                    continue;

		if (i != no) {
			var dist:Number = Distance(bots[no].pos, bots[i].pos, 10000);
			if ((nearestno == -1 || dist < nearestdis) && dist > 0 && bots[i].exist) {
				nearestno = i;
				nearestdis = dist;
			}
		}
	}
	return nearestno;
}
function Distance(p1:Point, p2:Point, maxdis:Number):Number {
	var dx:Number = Math.abs(p1.x - p2.x);
	var dy:Number = Math.abs(p1.y - p2.y);
	if (dx > maxdis) return -1;
	if (dy > maxdis) return -1;
	if (dx + dy > maxdis * 2) return -1;
	return (dx * dx + dy * dy);
}


function MouseClick(evt:MouseEvent):void {
	SelectBots(new Point(evt.stageX + curviewpoint.x, evt.stageY + curviewpoint.y));
}
function SelectBots(clickpos:Point):void {
	var mindist:Number;
	var minno:int = -1;

	var len:uint = bots.length;
    for (var i:uint = 0; i < len; i++) {
        if (bots[i].exist) {
			var dist:Number = Distance(clickpos, bots[i].pos, 20);
			if ((minno == -1 || dist < mindist) && dist > 0 && dist <= 256) {
				mindist = dist;
				minno = i;
			}
		}
	}
	
	if (minno > -1) {
		selectedbot = bots[minno];
	}
}

function MouseDown(evt:MouseEvent):void {
	if (evt.buttonDown) {
		mousedownpoint.x = evt.stageX;
		mousedownpoint.y = evt.stageY;
	}
}

function MouseMove(evt:MouseEvent):void {
	if (evt.buttonDown) {
		var mouseX:Number = evt.stageX;
		var mouseY:Number = evt.stageY;
		tempviewpoint.x = viewpoint.x - mouseX + mousedownpoint.x;
		tempviewpoint.y = viewpoint.y - mouseY + mousedownpoint.y;
		if (tempviewpoint.x < 0 - 200) tempviewpoint.x = 0 - 200;
		if (tempviewpoint.y < 0 - 200) tempviewpoint.y = 0 - 200;
		if (tempviewpoint.x > mapsizex - 465 + 200) tempviewpoint.x = mapsizex - 465 + 200;
		if (tempviewpoint.y > mapsizey - 465 + 200) tempviewpoint.y = mapsizey - 465 + 200;
	}
}

function MouseUp(evt:MouseEvent):void {
	viewpoint.x = tempviewpoint.x;
	viewpoint.y = tempviewpoint.y;
}

function KeyDown(evt:KeyboardEvent):void {
	if (evt.charCode == 32) paused = !paused;
	if (evt.charCode == 82 || evt.charCode == 114) selectedbot = null;
}


// View point following and updating
function UpdateViewpoint():void {
	if (selectedbot != null && selectedbot.exist) {
		tempviewpoint.x = selectedbot.pos.x - (465 / 2 - 50);
		tempviewpoint.y = selectedbot.pos.y - 465 / 2;
		viewpoint.x = curviewpoint.x;
		viewpoint.y = curviewpoint.y;
	}
	
	// Update view points
	curviewpoint.x = 0.92 * curviewpoint.x + 0.08 * tempviewpoint.x;
	curviewpoint.y = 0.92 * curviewpoint.y + 0.08 * tempviewpoint.y;
}


function DrawBots():void {
	var lbound:Number = curviewpoint.x - 20;
	var rbound:Number = curviewpoint.x + 465 + 20;
	var tbound:Number = curviewpoint.y - 20;
	var bbound:Number = curviewpoint.y + 465 + 20;
	
	var len:uint = bots.length;
	for (var i:uint = 0; i < len; i++) {
		if (bots[i].exist) {
			var px:Number = bots[i].pos.x;
			var py:Number = bots[i].pos.y;
			if (px > lbound && px < rbound && py > tbound && py < bbound) DrawBot(bots[i]);
		}
	}
}
function DrawBot(bot:Bot):void {
	var shape:Shape = BotShape(bot);

	shape.x = bot.pos.x - curviewpoint.x;
	shape.y = bot.pos.y - curviewpoint.y;
	shape.rotation = bot.dir;

	global.addChild(shape);
}
function BotShape(bot:Bot):Shape {
	var _shape:Shape = new Shape();
        var strength:Number = 1.3;
	_shape.graphics.lineStyle(2, bot.color);

	var sp:Point = new Point(0, -12);
	var sp2:Point = new Point(-6, 10);
	var sp3:Point = new Point(6, 10);

	_shape.graphics.moveTo(sp.x, sp.y);
	_shape.graphics.lineTo(sp2.x, sp2.y);
	_shape.graphics.lineTo(sp3.x, sp3.y);
	_shape.graphics.lineTo(sp.x, sp.y);
	
        // highlight Gods/Demigods a bit more
        if (bot.type == 1)
            strength = 1.9;

	_shape.filters = [new GlowFilter(bot.color, 1, 8, 8, strength, 2)];

	return _shape;
}

function DrawBullets():void {
	var lbound:Number = curviewpoint.x - 20;
	var rbound:Number = curviewpoint.x + 465 + 20;
	var tbound:Number = curviewpoint.y - 20;
	var bbound:Number = curviewpoint.y + 465 + 20;
	
	var len:uint = bullets.length;
	for (var i:uint = 0; i < len; i++) {
		if (bullets[i].exist) {
			var px:Number = bullets[i].pos.x;
			var py:Number = bullets[i].pos.y;
			if (px > lbound && px < rbound && py > tbound && py < bbound) DrawBullet(bullets[i]);
		}
	}
}
function DrawBullet(bullet:Bullet):void {
	var shape:Shape = BulletShape();

	shape.x = bullet.pos.x - curviewpoint.x;
	shape.y = bullet.pos.y - curviewpoint.y;
	shape.rotation = bullet.dir;

	global.addChild(shape);
}
function BulletShape():Shape {
	var _shape:Shape = new Shape();
	_shape.graphics.beginFill(0x00ffff, 1);

	_shape.graphics.drawCircle(0, 0, 2);

	_shape.graphics.endFill();

	return _shape;
}

function DrawMap():void {
	var shape:Shape = MapShape();
	
	shape.x = -curviewpoint.x;
	shape.y = -curviewpoint.y;
	shape.rotation = 0;
	
	global.addChild(shape);
}
function MapShape():Shape {
	var _shape:Shape = new Shape();
	_shape.graphics.lineStyle(2, 0x0088BB, 0.7);
	
	_shape.graphics.moveTo(0, 0);
	_shape.graphics.lineTo(mapsizex, 0);
	_shape.graphics.lineTo(mapsizex, mapsizey);
	_shape.graphics.lineTo(0, mapsizey);
	_shape.graphics.lineTo(0, 0);
	
	_shape.graphics.lineStyle(1, 0x0088BB, 0.7);
	
	for( var i:uint = 50; i < mapsizex; i+=50) {
		_shape.graphics.moveTo(i, 0);
		_shape.graphics.lineTo(i, mapsizey);
	}
	
	for( var j:uint = 50; j < mapsizey; j+=50) {
		_shape.graphics.moveTo(0, j);
		_shape.graphics.lineTo(mapsizex, j);
	}
	
	return _shape;
}

function DrawMinimap():void {
	var shape:Array = MinimapShape();
	var shape2:Shape = MiniFOVShape();
	
	shape2.x = 365 + curviewpoint.x / 10;
	shape2.y = curviewpoint.y / 10;
	
	global.addChild(shape[0]);
	global.addChild(shape[1]);
	global.addChild(shape2);
	
	var len:uint = bots.length;
	for (var i:uint = 0; i < len; i++) {
		if (bots[i].exist) DrawMiniBot(bots[i]);
	}
}
function MinimapShape():Array {
	var minimapx:Number = mapsizex / 10;
	var minimapy:Number = mapsizey / 10;

	var shape:Array = [];
	
	var _shape:Shape = new Shape();
	_shape.graphics.beginFill(0x0088BB, 0.4);
	
	_shape.graphics.moveTo(365, 0);
	_shape.graphics.lineTo(365 + minimapx, 0);
	_shape.graphics.lineTo(365 + minimapx, minimapy);
	_shape.graphics.lineTo(365, minimapy);
	_shape.graphics.lineTo(365, 0);
	
	_shape.graphics.endFill();
	
	var _shape2:Shape = new Shape();
	_shape2.graphics.beginFill(0x00001E, 0.4);
	
	_shape2.graphics.moveTo(366 , 1);
	_shape2.graphics.lineTo(365 + minimapx - 1, 1);
	_shape2.graphics.lineTo(365 + minimapx - 1, minimapy - 1);
	_shape2.graphics.lineTo(366, minimapy - 1);
	_shape2.graphics.lineTo(366, 1);
	
	_shape2.graphics.endFill();
	
	shape.push(_shape);
	shape.push(_shape2);
	
	return shape;
}
function MiniFOVShape():Shape {
	var _shape:Shape = new Shape();
	_shape.graphics.lineStyle(1, 0x0088BB, 0.5);
	
	_shape.graphics.moveTo(0, 0);
	_shape.graphics.lineTo(46.5, 0);
	_shape.graphics.lineTo(46.5, 46.5);
	_shape.graphics.lineTo(0, 46.5);
	_shape.graphics.lineTo(0, 0);
	
	return _shape;
}

function DrawMiniBot(bot:Bot):void {
	var shape:Shape = MiniBotShape(bot);

	shape.x = 365 + bot.pos.x / 10;
	shape.y = bot.pos.y / 10;

	global.addChild(shape);
}
function MiniBotShape(bot:Bot):Shape {
	var _shape:Shape = new Shape();
	_shape.graphics.beginFill(bot.color, 1);

	_shape.graphics.drawCircle(0, 0, 1);

	_shape.graphics.endFill();

	return _shape;
}

function DrawSelectedBot():void {
	// Unselect non-exist bot
	if (selectedbot != null) {
		if (selectedbot.exist) {
			var shape:Shape = new Shape();
			shape.graphics.lineStyle(2, 0xffffff, 0.5);
			
			shape.graphics.drawCircle(0, 0, 16);
			shape.graphics.moveTo(6, -19);
			shape.graphics.lineTo(0, -23);
			shape.graphics.lineTo(-6, -19);
			
			shape.filters = [new GlowFilter(0xffffff, 1, 8, 8, 3, 2)];
			
			shape.x = selectedbot.pos.x - curviewpoint.x;
			shape.y = selectedbot.pos.y - curviewpoint.y;
			shape.rotation = selectedbot.dir;
			
			global.addChild(shape);
		}
		else {
			selectedbot = null;
		}
	}
}

function DrawBotStatus():void {
	// Unselect non-exist bot
	if (selectedbot != null) {
		if (selectedbot.exist) {
			var shape:Array = BotStatusShape();
                        var target:String = "";
			global.addChild(shape[0]);
			global.addChild(shape[1]);

                        if (selectedbot.target != null && selectedbot.target.exist)
                            target = selectedbot.target.name;
			
			stField.text = String(selectedbot.name) + "\n"
						+ "\n"
						+ "Posx: " + String(getPoint(selectedbot.pos.x, 1)) + "\n"
						+ "Posy: " + String(getPoint(selectedbot.pos.y, 1)) + "\n"
						+ "Direction: " + String(getPoint(selectedbot.dir, 1)) + "\n"
						+ "\n"
						+ "HP: " + String(getPoint(selectedbot.hp, 0)) + "/" + String(getPoint(selectedbot.maxhp, 0)) + "\n"
						+ "MaxSpeed: " + String(getPoint(selectedbot.speed, 1)) + "\n"
						+ "MaxTurn: " + String(getPoint(selectedbot.turn, 1)) + "\n"
						+ "ShotSpeed: " + String(getPoint(selectedbot.shotspeed, 1)) + "\n"
						+ "BulletDamage: " + String(getPoint(selectedbot.bdamage, 1)) + "\n"
						+ "BulletSpeed: " + String(getPoint(selectedbot.bspeed, 1)) + "\n"
						+ "BulletLife: " + String(getPoint(selectedbot.blifespan, 1)) + "\n"
						+ "BulletDeviation: " + String(getPoint(selectedbot.bdev, 1)) + "\n"
						+ "Shield: " + String(getPoint(selectedbot.shield, 1)) + "\n"
						+ "Regeneration: " + String(getPoint(selectedbot.regen, 1)) + "\n"
						+ "\n"
						+ "Kills: " + String(selectedbot.kills) + "\n"
						+ "Cash: " + String(selectedbot.cash) + "\n"
                                                + "\n"
                                                + "Hate: " + String(selectedbot.targethate) + "\n"
                                                + target;
			global.addChild(stField);
		}
		else {
			selectedbot = null;
		}
	}	
}
function BotStatusShape():Array {
	var shape:Array = [];
	
	var _shape:Shape = new Shape();
	_shape.graphics.beginFill(0x0088BB, 0.4);
	
	_shape.graphics.moveTo(365, 100);
	_shape.graphics.lineTo(365, 465);
	_shape.graphics.lineTo(465, 465);
	_shape.graphics.lineTo(465, 100);
	_shape.graphics.lineTo(365, 100);
	
	_shape.graphics.endFill();
	
	var _shape2:Shape = new Shape();
	_shape2.graphics.beginFill(0x00001E, 0.4);
	
	_shape2.graphics.moveTo(366, 101);
	_shape2.graphics.lineTo(366, 464);
	_shape2.graphics.lineTo(464, 464);
	_shape2.graphics.lineTo(464, 101);
	_shape2.graphics.lineTo(366, 101);
	
	_shape2.graphics.endFill();
	
	shape.push(_shape);
	shape.push(_shape2);
	
	return shape;
}

function DrawTextField():void {
	tField.text = "Frames: " + String(ticks)
				+ "    Bots:" + String(bots.length) + "    Bullets:" + String(bullets.length) + "\n"; //Unsort-out bots and bullets
	tField.text = tField.text + "mouseX:" + String(global.mouseX) + "    mouseY:" + String(global.mouseY)
				+ "    cFOVx: " + String(int(curviewpoint.x)) + "    cFOVy: " + String(int(curviewpoint.y));
				
	global.addChild(tField);
}

function DrawPaused():void {
	if (paused) {
		var tFormat:TextFormat = new TextFormat;
		tFormat.font = "Arial";
		tFormat.bold = false;
		tFormat.color = 0xffffff;
		tFormat.size = 20;
		tFormat.align = TextFormatAlign.CENTER;

		var textField:TextField = new TextField;
		textField.defaultTextFormat = tFormat;
		textField.selectable = false;
		textField.x = 365;
		textField.y = 435;
		textField.width = 100;
		textField.height = 30;
		textField.text = "PAUSED";
		textField.filters = [new GlowFilter(0xffffff, 1, 2, 2)];
		
		global.addChild(textField);
	}
}


class Bot {
	function Bot(_name:String, _pos:Point, _dir:Number,
			_maxhp:Number, _type:uint,
			_speed:Number, _turn:Number,
			_shotspeed:uint,
			_bdamage:Number, _bspeed:Number,
			_blifespan:uint, _bdev:Number,
			_shield:Number, _regen:Number,
                        _cash:uint, _prob:uint,
                        _color:uint,
			_exist:Boolean = false) {
		this.hp = _maxhp;
		this.maxhp = _maxhp;
                this.type = _type;
		this.exist = _exist;
		this.name = _name;
                if (_pos == null)
                   this.pos = null;
                else
		   this.pos = new Point(_pos.x, _pos.y);
		this.dir = _dir;
		this.speed = _speed;
		this.turn = _turn;
		this.shotspeed = _shotspeed;
		this.bdamage = _bdamage;
		this.bspeed = _bspeed;
		this.blifespan = _blifespan;
		this.bdev = _bdev;
		this.shield = _shield;
		this.regen = _regen;
		this.cash = _cash;
                this.prob = _prob;
                this.color = _color;
		this.kills = 0;
                this.target = null;
                this.targethate = 0;
	}

	public static function StatInstance(_name:String,
			_maxhp:Number, _type:uint,
			_speed:Number, _turn:Number,
			_shotspeed:uint,
			_bdamage:Number, _bspeed:Number,
			_blifespan:uint, _bdev:Number,
			_shield:Number, _regen:Number,
                        _prob:uint, _color:uint):Bot {
                return new Bot(_name, null, 0, _maxhp, _type, _speed, _turn, _shotspeed, _bdamage, _bspeed, _blifespan, _bdev, _shield, _regen, 0, _prob, _color, false);
        }


        public function Clone(_point:Point, _dir:uint, _exist:Boolean = false):Bot {
                return new Bot(name, _point, _dir, maxhp, type, speed, turn, shotspeed, bdamage, bspeed, blifespan, bdev, shield, regen, cash, prob, color, _exist);
        }
	
	public var hp:Number;
	public var maxhp:Number;

	public var exist:Boolean;
	public var name:String;				// Unique name 

        public var color:uint;                          // Color
        public var prob:uint;                           // Probability that this bot gets generated
	
	public var pos:Point;				// Position in Point
	public var dir:Number;				// Direction in degrees

	public var speed:Number;			// Move speed in pixels/s
	public var turn:Number;				// Rotate speed in degrees/s
	
	public var shotspeed:uint;
	
	public var bdamage:Number; 			// Bullet damage
	public var bspeed:Number; 			// Bullet speed in pixels/s
	public var blifespan:uint; 			// Bullet lifespan in frames
	
	public var bdev:Number; 			// Bullet direction deviation in degrees
	
	public var shield:Number;			// Shield
	public var regen:Number;			// Regeneration in 1/s
	
	public var kills:uint;
	public var cash:uint;

        public var type:uint;                           // Type of bot, determines AI and color

        public var target:Bot;                          // Current AI Target
        public var targethate:uint;                     // Frames of hate for target
	
	public function FaceToPosition(pos:Point):void {
		var temp:Number = this.turn;

		var theta:Number = Math.atan2(pos.y - this.pos.y, pos.x - this.pos.x);
		theta = (theta * 180 / Math.PI - this.dir + 810) % 360;
		if (1 <= theta && theta <= 179) {
			if (temp > theta) temp = theta;
			this.dir = this.dir + temp;
		}
		else if (181 <= theta && theta <= 359) {
			if (temp > 360 - theta) temp = 360 - theta;
			this.dir = this.dir - temp;
		}
	}

        public function AddHate(attacker:Bot, amount:uint):void {
                if (type == 4)
                        amount *= 3;

                if (attacker == target)
                        targethate += amount;
                else {
                        if (targethate <= amount)
                        {
                                // switch targets
                                target = attacker;
                                targethate = 180 + (amount - targethate); // 3 seconds of "hate buffer"
                        }
                        else
                                targethate -= amount;
                }
        }
}

class Bullet {
	function Bullet(_bot:Bot, _pos:Point, _dir:Number,
					_damage:Number, _speed:Number, _lifespan:uint,
					_lifetime:uint = 0,
					_exist:Boolean = true) {
		this.damage = _damage;
		this.exist = _exist;
		this.bot = _bot;
		this.pos = new Point(_pos.x, _pos.y);
		this.dir = _dir;
		this.lifetime = _lifetime;
		this.speed = _speed;
		this.lifespan = _lifespan;
	}
	
	public var damage:Number;
	
	public var exist:Boolean;
	public var bot:Bot;					// Belongs to which bot

	public var pos:Point;				// Position in Point
	public var dir:Number;				// Direction in degrees
	public var lifetime:uint;			// Lifetime in frames

	public var speed:Number;			// Move speed in pixels
	public var lifespan:uint;			// Lifespan in frames	
}

function getPoint(num:Number, l:int):Number {
    return (Math.round(num * Math.pow(10, l)) / Math.pow(10, l));
}