module br.enemy;

private import util.parts;
private import util.particle;
private import util.collision;
private import util.basis;
private import util.animationImpl;
private import br.shapeImpl;
private import br.screen;
private import br.mainloop;
private import br.gamemanager;
private import br.bullet;
private import br.boss;
private import br.star;
private import br.shot;
private import br.laserImpl;
private import br.particleImpl;
private import br.sound;


public Enemy makeEnemy(char[] type ,Vector3 pos ,Vector3 vel ,Object par){
	Enemy e = null;
	switch(type){
		
		case "1" :e = new Enemy1(pos ,vel);break;
		case "capsule":e = new StarCapsule(pos ,vel);break;
		case "a" :e = new EnemyA(pos ,vel ,par);break;
		case "b" :e = new EnemyB(pos ,vel );break;
		case "c" :e = new EnemyC(pos ,vel );break;
		case "d" :e = new EnemyD(pos ,vel );break;
		case "e" :e = new EnemyE(pos ,vel );break;
		case "f" :e = new EnemyF(pos ,vel ,par);break;
		case "mine":e = new Mine(pos ,vel);break;
		case "middle":e = new MiddleEnemy(pos ,vel );break;
		case "laser":e = new LaserEnemy(pos ,vel);break;
		case "wall":e = new WallEnemy(pos ,vel);break;
		case "boss1":e = new Boss1(pos,vel);break;
		case "boss2":e = new Boss2(pos,vel);break;
		case "boss3":e = new Boss3(pos,vel);break;
		case "boss4":e = new Boss4(pos,vel);break;
		default:break;
		
	}
	return e;
	
}


public class Enemy:Parts{
	public:
	float hp;
	bool vincible;
	bool border;
	double dam;
	public this(float hp ,Vector3 pos ){
		collisionManager.add(this ,collisionManager.kind.SHIP ,2);
		collisionManager.add(this ,collisionManager.kind.SHOT ,2);
		this.pos = cast(Vector3)pos.clone();
		rpos = cast(Vector3)pos.clone();
		
		drawing =   POLYGON | WIRE;
		
		wR = 0.0;wG =0.0f;wB = 0.0f;walpha = 1.0;
		this.hp = hp;
		if(hp < 0)vincible = false;
		else vincible = true;
		
		enemyManager.add(this);
		
		border = true;
		dam = 0;
	}
	
	public void move(){
		super.move();
		if(border && (rpos.y+size < screen.GAME_DOWN || screen.GAME_UP < rpos.y-size ||
			screen.GAME_RIGHT  < rpos.x-size || rpos.x+size < screen.GAME_LEFT ||
			screen.GAME_NEAR < rpos.z - size || rpos.z + size < screen.GAME_FAR
			
		)){
			vanish();
		}
		if((1e-6) < dam){
			
			double radZ ,radX;
			radZ = rand.nextFloat(PI * 2.0);
			radX = rand.nextFloat(PI);
			vibrate(radZ ,radX ,dam/10.0);
			
			dam -= mulsp(0.1);
		}else dam = 0.0;
		
		
	}
	public override void reportCollision(int kind ,Parts p){
		switch(kind){
			case CollisionManager.kind.SHOT:
			
				damage(Shot.POWER);
				
			
			break;
			case CollisionManager.kind.SHIP:
			
				damage(3);
			
			break;
			default:break;
		}
		
	}
	
	public void attack(char[] type){}
	public void damage(float d){
		double dd;
		dd = 1.0;
		if(vincible){
			hp -= d;
			if(hp <= 0)destroy();
			//0.5 + 0.6 * fmin(1.0 ,fmax(0.0 ,(ship.laserSpeed - ship.laserMinSpeed) / (ship.laserMaxSpeed - ship.laserMinSpeed)));
			
			
		}else{
				
				dd *= 0.1;
		}
		
		dam = fmin(3.0 ,dam+dd);
	}
	public void destroy(){
		super.destroy();
		destroyImpl();
		
	}
	public void destroyImpl(){
		makeParticleByShape(shape, 1 ,size/1 , drawing ,rpos ,new Vector3() ,R ,G ,B,0.4,0.4,0.4 ,alpha*1.5 ,5.0);
		Sound_PlaySe(se_kind.DON);
	}
	
	public void setFlyColor(){
		R = 0.9;G =0.8;B = 1.0;alpha = 1.0;
	}
	public void setMiddleColor(){
		R = 0.8;G = 0.9;B = 1.0;alpha = 1.0;
	}
	public void setBossColor(){
		R = 1.0;G =1.0;B = 1.0;alpha = 1.0;
	}
	public void size(double s){
		super.size(s);
		collisionRange = size / 2.0f;
	}
	public double size(){
		return super.size();
	}
}

public class EnemyAppend:Enemy{
	private:
	int vanishCount;
	bool parentExist;
	bool diff;
	int vc;
	public this(Shape shape ,double size ,float hp = -1  ,double R = 1.0,double G = 1.0 ,double B = 1.0,double alpha = -1.0,bool diff = true ,int vc = 10){
		super(hp ,new Vector3());
		this.shape = cast(Shape)shape.clone();
//		Log_write("a");
//		drawing = WIRE ;
		this.R = R;this.G = G;this.B = B;this.alpha = alpha;
		this.size = size;
		this.collisionRange = size / 2.0;
		parentExist = true;
		
		drawing = WIRE | POLYGON;
		
		border = false;
		this.diff = diff;
		this.vc = vc;
	}
	
	public void move(){
		
		
		
		if(parentExist & (parent is null || parent.exists == false)){
			parentExist = false;
			vanishCount = cast(int)divsp(vc);
			
		}
		
		if(parentExist){
			super.move();
		}
		
		if(parentExist == false){
			vanishCount --;
			if(vanishCount < 0)destroy();
		}
	}
	public void damage(float d){
		if(vincible){
			hp -= d;
			if(hp <= 0)destroy();
		}else if(parentExist & (parent !is null && parent.exists) && diff){
			(cast(Enemy)parent).damage(d);
		}
	}
	public void destroy(){
		super.destroy();
//		makeParticle(shape, size ,WIRE ,rpos ,new Vector3() ,rpose ,R ,G ,B ,alpha);
	}

}

public class Hammer:EnemyAppend{
	Vector3 pre;
	public this(Shape shape ,double size ,float hp = -1 ,double R = 1.0,double G = 1.0 ,double B = 1.0,double alpha = -1.0){
		super(shape,size,hp,R,G,B,alpha);
		pre = new Vector3();
		rpos = new Vector3();
	}
	public void move(){
		pre = cast(Vector3)rpos.clone();
		super.move();
		if(rpos.dist(pre) > 10.0f){
			if(cnt%3 == 0)makeParticle(shape, size ,WIRE ,rpos ,new Vector3() ,rpose ,R ,G ,B,R,G,B ,alpha);
		}
	}
}
public class Finger:EnemyAppend{
	Vector3 pre;
	public this(Shape shape ,double size ,float hp = -1 ,double R = 1.0,double G = 1.0 ,double B = 1.0,double alpha = -1.0){
		super(shape,size,hp,R,G,B,alpha);
	}
	public void attack(char[] type){
		switch(type){
			case "a":
			double rad = poseDirection();
			new Enemy2acc(rpos ,new Vector3(cos(rad) ,sin(rad) ,0.0f)*0.5f ,2);
			break;
			case "b":
			double rad = poseDirection();
			new Enemy1(rpos ,new Vector3(cos(rad) ,sin(rad) ,0.0f) ,15);
			break;
			default:break;
		}
	}
}
public class RootAppend:EnemyAppend{
	Vector3 pre;
	public this(Shape shape ,double size ,float hp = -1 ,double R = 1.0,double G = 1.0 ,double B = 1.0,double alpha = -1.0){
		super(shape,size,hp,R,G,B,alpha);
	}
	public void attack(char[] type){
		switch(type){
			case "laser":
			Vector3 aim = new Vector3(0.0f ,-100.0f ,-800.0f)-rpos;
			double rad = atan2(aim.y,aim.x)+(rand.nextFloat(50.0f)-25.0)/180.0*PI;//poseDirection();
			Vector3 vel = new Vector3(cos(rad) ,sin(rad) ,0.0f);
			Vector3 p;
			for(double r=0.0;r<60.0;r+=12.0){
				p = rpos+vel*r;
				new Enemy2(new Vector3(p.x,p.y,-800) ,vel*3.7f ,3);
			}
			break;
			case "elaser":
//			Vector3 aim = poseDirection();
			double rad = poseDirection()-PI;//atan2(aim.y,aim.x)+(rand.nextFloat(50.0f)-25.0)/180.0*PI;//poseDirection();
			Vector3 vel = new Vector3(cos(rad) ,sin(rad) ,0.0f);
			Vector3 p;
			for(double r=0.0;r<120.0;r+=30.0){
				p = rpos+vel*r;
				new Bullet1(new Vector3(p.x,p.y,-800) ,vel*4.5f );//vel * -0.02f ,1.5f );
			}
			break;
			case "balkan":
//			Vector3 aim = poseDirection();
			double rad = poseDirection()-PI;//atan2(aim.y,aim.x)+(rand.nextFloat(50.0f)-25.0)/180.0*PI;//poseDirection();
			Vector3 vel;
			Vector3 p;
			for(double r=-PI/6.0;r<=PI/6.0;r+=PI/36.0){
				vel = new Vector3(cos(rad+r) ,sin(rad+r) ,0.0f);
				p = rpos+vel*r*50.0f;
				new Enemy2acc(new Vector3(p.x,p.y,-800) ,vel*0.9f ,2);
			}
			break;
			case "rock":
//			Vector3 aim = poseDirection();
			double rad = poseDirection()-PI;//atan2(aim.y,aim.x)+(rand.nextFloat(50.0f)-25.0)/180.0*PI;//poseDirection();
			Vector3 vel;
			Vector3 p;
//			for(double r=-PI/6.0;r<=PI/6.0;r+=PI/12.0){
				vel = new Vector3(cos(rad) ,sin(rad) ,0.0f);
				p = rpos;//+vel*r*20.0f;
				new Enemy1(new Vector3(p.x,p.y,-800) ,vel*1.5f ,40);
//			}
			break;
			case "reflect":
//			float x = 0.0f + (2.0f + rand.nextFloat(4.0f))*(1.0f-cast(float)((sCnt/120)%2)*2.0f);
			double rad = poseDirection()-PI;
			Vector3 v = new Vector3(cos(rad) ,sin(rad) ,0.0f) * 4.0f;//new Vector3(cos(rad)*6.0f ,-4.0f ,0.0f);//sin(rad)*6.0f,0.0f);;
			Parts p = new ReflectBullet(rpos ,v);
			Parts p1 = new BulletAppend();
			Parts p2 = new BulletAppend();
			Parts p3 = new BulletAppend();
			p.addChild(p1, "1", 40 ,FOLLOW);
			p1.addChild(p2 ,"2" ,40 ,FOLLOW);
			p2.addChild(p3 ,"2" ,40 ,FOLLOW);
			break;
			default:break;
		}
	}
}

public class BulletEnemy:Enemy{
	public:
	Vector3 vel;
	float msize;
	public this(Vector3 pos ,Vector3 vel ,float hp = 3 ,float size = -1.0f){
		super(hp ,pos);
		this.vel = cast(Vector3)vel.clone();
		
		if(size<0)msize =sqrt(cast(float)hp) * 15.0f;
		else msize = size;
		this.size = fmin(30.0f ,msize);
		collisionRange = size /2.0f;
		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
		setFlyColor();
	}
	public void move(){
		super.move();
		/*
		if(cnt  == 60){
			attack("a");
		}
		*/
		pos += mulsp(vel);
		
		if(msize - size > 1.0f){
			size = size + mulsp(0.5f);
			collisionRange = size /2.0f;
		}else{
			 size = msize;
			 collisionRange = size /2.0f;
		}
		
		
//		poseY += mulsp(1f);
	}
	public void attack(char[] type){
//		Vector3 v = vec3Normalize(ship.rpos -rpos) * 1.0f;
//			new Bullet(rpos ,v);
	}
	
	
}


public class Enemy1:BulletEnemy{
	public:
	static Shape sshape;
	public this(Vector3 pos ,Vector3 vel ,float hp = 3 ,float size = -1.0f){
		super(pos ,vel ,hp ,size);
		shape = getShape();
		//Cube.getShape();
	}
	protected static Shape setShape(){
		return new SH_Sphere(6);
	}
	public void move(){
		super.move();
		poseY += mulsp(1f);
		poseX += mulsp(2f);
	}
	public static Shape getShape(){
		if(sshape is null)sshape = setShape();
		return cast(Shape)sshape.clone();
	}

}
public class Enemy2:BulletEnemy{
	public:
	static Shape sshape;
	public this(Vector3 pos ,Vector3 vel ,float hp = 3 ,float size = -1.0f){
		super(pos ,vel ,hp ,size);
		shape = getShape();//Cube.getShape();
	}
	public void move(){
		super.move();
		poseX += mulsp(2f);
	}
	protected static Shape setShape(){
		return  OctaShape.getShape(1.5f ,2.0f);
	}
	public static Shape getShape(){
		if(sshape is null)sshape = setShape();
		return cast(Shape)sshape.clone();
	}
	
}
public class Enemy2acc:BulletEnemy{
	public:
	static Shape sshape;
	public this(Vector3 pos ,Vector3 vel ,float hp = 3){
		super(pos ,vel ,hp);
		shape = getShape();//Cube.getShape();
	}
	public void move(){
		super.move();
		vel *= 1.0f + mulsp(0.02f);
		poseX += mulsp(2f);
	}
	protected static Shape setShape(){
		return  OctaShape.getShape(1.5f ,2.0f);
	}
	public static Shape getShape(){
		if(sshape is null)sshape = setShape();
		return cast(Shape)sshape.clone();
	}
	
}
public class Mylmidon:BulletEnemy{
	public:
	static Shape sshape;
	public this(Vector3 pos ,Vector3 vel ,float hp = 3 ,float size=-1){
		super(pos ,vel ,hp ,size);
		//Cube.getShape();
		R = 0.05f;G = 0.05f;B = 0.05f;alpha = 1.0f;
		this.size = msize;
		poseZ += 90;
		drawing = POLYGON;
	}
	protected static Shape setShape(){
		return  new SH_Sphere(7,1.0f,1.0f);
	}
	public static Shape getShape(){
		if(sshape is null)sshape = setShape();
		return cast(Shape)sshape.clone();
	}
	public override void reportCollision(int kind ,Parts p){
		super.reportCollision(kind ,p);
		dam = 0;
	}
}
public class Mylmidon1:Mylmidon{
	
	public this(Vector3 pos ,Vector3 vel ,float hp = 3 ,float size=-1.0){
		super(pos ,vel ,hp);
		shape = getShape();
	}
	public void move(){
		super.move();
		poseZ += mulsp(1f);
//		poseX += 1.0f;
//		vel *= 1.0f + mulsp(0.02f);
	}
	
	
	
}
public class Mylmidon1acc:Mylmidon{
	
	public this(Vector3 pos ,Vector3 vel ,float hp = 3 ,float size=-1.0){
		super(pos ,vel ,hp);
		shape = getShape();
	}
	public void move(){
		super.move();
		poseZ += mulsp(1f);
		vel *= 1.0f + mulsp(0.02f);
	}
	
	
}
public class MylmidonBomb:Mylmidon{
	
	public this(Vector3 pos ,Vector3 vel ,float hp = 3 ,float size=-1.0){
		super(pos ,vel ,hp ,size);
		shape = getShape();
	}
	public void move(){
		super.move();
		poseZ += mulsp(1f);
		vel *= 1.0f - mulsp(0.02f);
		if(vel.size<0.1f){
			attack("a");
			destroy();
		}
//		poseX += 1.0f;
//		vel *= 1.0f + mulsp(0.02f);
	}
	public void attack(char[] type){

		Vector3 vel = vec3Normalize(ship.rpos-rpos);
		new AccBullet(rpos ,new Vector3(),vel*0.03);
		
	}
	
	
}
public class MylmidonCell:Mylmidon{
	public double rad;
	public bool par;
	public Parts child;
	private int num;
	private real aimBin;
	private float maxhp;
	public this(Vector3 pos ,double rad ,real aim,int num, float hp = 3 ,float size=-1.0){
		super(pos ,new Vector3() ,hp ,size);
		shape = getShape();
		this.rad = rad;
		par = false;
		this.num = num;
		this.aimBin = aim;
		maxhp = hp;
	}
	public void move(){
		super.move();
//		poseZ += mulsp(1f);
//		vel *= 1.0f - mulsp(0.02f);
		if(cnt==1){
			attack("a");
		}
		
		if(par && !(parent !is null && parent.exists))destroy();
		if(!par && cnt == divsp(300))vanish();
		if(child !is null && !child.exists())destroy();
		size = cast(real)hp / cast(real)maxhp * 30 + 10;
//		poseX += 1.0f;
//		vel *= 1.0f + mulsp(0.02f);
	}
	public void attack(char[] type){
		if(num > 0){
			child = new MylmidonCell(new Vector3(),0.0,aimBin,num-1,hp,size);
			if(!par){
				addChild(child,"a",size,NORMAL ,matRotateZ(0));(cast(Enemy)child).border = false;
				child.linkZ = -90.0*aimBin;
				child.addAnimation(new RotateTo(300 ,LINKZ ,30*aimBin) ,"swing");
			}else{
				addChild(child,"a",size,NORMAL ,matRotateZ(0));(cast(Enemy)child).border = false;
				child.linkZ = -30.0*aimBin;
				child.addAnimation(new RotateTo(300 ,LINKZ ,10*aimBin) ,"swing");
			}
			(cast(MylmidonCell)child).par = true;
//			child.addAnimation(new Magnification(60, 40) ,"mag");
		}
	}
	
	
}

public class Missile:Enemy{
	public:
	Vector3 vel;
	Vector3 acc;
	public this(Vector3 pos ,Vector3 vel ,Vector3 acc){
		super(3 ,pos);
		this.vel = cast(Vector3)vel.clone();
		this.acc = cast(Vector3)acc.clone();
		
		shape = MissileShape.getShape();
		size = 40.0f;
		collisionRange = 20.0f;
		poseZ = -90.0;//atan2(vel.y,vel.x)*180.0/PI;
		
		setFlyColor();
		
	}
	public void move(){
		super.move();
		if(cnt  == divsp(60)){
			attack("a");
		}
		
		pos += mulsp(vel);
		vel += mulsp(acc);
		
		poseX += mulsp(2f);
//		poseY += 1f;
	}
	public void attack(char[] type){
//		Vector3 v = vec3Normalize(ship.rpos -rpos) * 1.0f;
//			new Bullet(rpos ,v);
	}
}
public Shape CAPSULESHAPE;
public class StarCapsule:Enemy{
	public:
	Vector3 vel;
	
	
	
	public this(Vector3 pos ,Vector3 vel ){
		super(20 ,pos);
		this.vel = cast(Vector3)vel.clone();
		
		if(CAPSULESHAPE is null){
			Shape s1 = new SH_Regular(8);
			Shape s2 = StarShape.getShape().scalef(0.8f,0.8f,0.8f);
			CAPSULESHAPE = s1 + s2;
		}
		shape = cast(Shape)CAPSULESHAPE.clone();
		size = 30.0f;
		collisionRange = 15.0f;
//		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
		R = 1.0;G =1.0;B = 0.8;alpha = 1.0;
	}
	public void move(){
		super.move();
		pos += mulsp(vel);
		
		poseZ += mulsp(3f);
	}
	public void attack(char[] type){
		
	}
	public void destroy(){
		
		new Star2(rpos ,new Vector3());
		super.destroy();
		
	}
	
}
public class EnemyA:Enemy{
	
	public:
	Vector3 vel;
	Vector3 acc;
	
	
	
	public this(Vector3 pos ,Vector3 vel ,Object o ){
		super(10 ,pos);
		this.vel = cast(Vector3)vel.clone();
		if(o is null || !is(o == Vector3))this.acc = cast(Vector3)vel.clone() * -0.01f;
		else this.acc = cast(Vector3)(cast(Vector3)o).clone();
		this.acc = (cast(Vector3)vel.clone()) * -0.01f;
		
		shape = Cube.getShape();
		size = 30.0f;
		collisionRange = 15.0f;
//		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
		setFlyColor();
	}
	public void move(){
		super.move();
		pos += mulsp(vel);
		vel += mulsp(acc);
		
		poseX += mulsp(2f);
		poseY += mulsp(1f);
	}
	public void attack(char[] type){
		
	}
	
}
public class EnemyB:Enemy{
	
	public:
	Vector3 vel;
//	Vector3 acc;
	
	
	
	public this(Vector3 pos ,Vector3 vel ){
		super(15 ,pos);
		this.vel = cast(Vector3)vel.clone();
//		if(o is null || !is(o == Vector3))this.acc = cast(Vector3)vel.clone() * -0.01f;
//		else this.acc = cast(Vector3)(cast(Vector3)o).clone();
//		this.acc = (cast(Vector3)vel.clone()) * -0.01f;
		
		shape = Octahedron.getShape();
		size = 30.0f;
		collisionRange = 15.0f;
//		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
		setFlyColor();
	}
	public void move(){
		super.move();
		if(cnt % divsp(60)==0)attack("a");
		
		pos += mulsp(vel);
		vel.y *= 0.98;//mulsp(acc.x);
		
		poseX += mulsp(2f);
		poseY += mulsp(1f);
	}
	public void attack(char[] type){

		Vector3 v = new Vector3(0.0f ,-3.0f ,0.0f);//new Vector3(cos(rad)*6.0f ,-4.0f ,0.0f);//sin(rad)*6.0f,0.0f);;
		for(double y=0.0;y<100.0f;y+=30.0f){
			new Enemy2(rpos+new Vector3(0.0f,-y,0.0f) ,v ,5 ,20);
		}
		
	}
	
}

public Shape ENEMYCSHAPE;
public class EnemyC:Enemy{
	
	public:
	Vector3 vel;
	float dx;
//	Vector3 acc;
	
	
	
	public this(Vector3 pos ,Vector3 vel ){
		super(3 ,pos);
		this.vel = cast(Vector3)vel.clone();
//		if(o is null || !is(o == Vector3))this.acc = cast(Vector3)vel.clone() * -0.01f;
//		else this.acc = cast(Vector3)(cast(Vector3)o).clone();
//		this.acc = (cast(Vector3)vel.clone()) * -0.01f;
		
		if(ENEMYCSHAPE is null){
			Shape s1 = OctaShape.getShape(1.0f ,2.0f).translate(0,0.5f,0);
			Shape s2 = OctaShape.getShape(1.0f ,2.0f).translate(0,-0.5f,0);
			ENEMYCSHAPE = s1 + s2;
		}
		shape = cast(Shape)ENEMYCSHAPE.clone();
		size = 20.0f;
		collisionRange = 10.0f;
		
		dx = vel.x;
//		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
		poseZ = -90.0;
		
		setFlyColor();
	}
	public void move(){
		super.move();
		
		pos += mulsp(vel);
		vel.x = dx * cos(mulsp(cast(double)(cnt%120))/60.0*PI);//mulsp(acc.x);
		
		poseX += mulsp(2f);
//		poseY += mulsp(1f);
	}
	public void attack(char[] type){
/*
		Vector3 v = new Vector3(0.0f ,-3.0f ,0.0f);//new Vector3(cos(rad)*6.0f ,-4.0f ,0.0f);//sin(rad)*6.0f,0.0f);;
		for(double y=0.0;y<100.0f;y+=30.0f){
			new Enemy2(rpos+new Vector3(0.0f,-y,0.0f) ,v ,5 ,20);
		}
*/		
	}
	
}
public Shape ENEMYDSHAPE;
public class EnemyD:Enemy{
	
	public:
	Vector3 vel;
	float dx;
//	Vector3 acc;
	float dy;
	int stop;
	bool stopped;
	
	public this(Vector3 pos ,Vector3 vel){
		super(15 ,pos);
		this.vel = cast(Vector3)vel.clone();
//		if(o is null || !is(o == Vector3))this.acc = cast(Vector3)vel.clone() * -0.01f;
//		else this.acc = cast(Vector3)(cast(Vector3)o).clone();
//		this.acc = (cast(Vector3)vel.clone()) * -0.01f;
		
		if(ENEMYDSHAPE is null){
			Shape s = OctaShape.getShape(1.0f ,1.0f).transformMatrix(matRotateZ(-90));;
			Shape s1 = OctaShape.getShape(0.6f ,3.0f).scalef(0.8f,0.8f,0.8f).transformMatrix(matTranslate(1.5f,0.0f,0.0f)*matRotateZ(45));
			Shape s2 = OctaShape.getShape(0.6f ,3.0f).scalef(0.8f,0.8f,0.8f).transformMatrix(matTranslate(1.5f,0.0f,0.0f)*matRotateZ(135));
			ENEMYDSHAPE = s + s1 + s2;
		}
		shape = cast(Shape)ENEMYDSHAPE.clone();
		size = 15.0f;
		collisionRange = 10.0f;
		
		dy = vel.y / 90.0f;
//		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
//		poseZ = -90.0;
		
		setMiddleColor();
		stop = 0;
		stopped = false;
	}
	public void move(){
		super.move();
		
		if(stop<=0){
			pos += mulsp(vel);
			vel.y -= mulsp(dy);
		}else{
			if(cnt % 8 == 0){
				attack("a");
			}
			stop --;
		}
		if(!stopped && abs(vel.y) < mulsp(0.5f)){
			stop = 30;
			stopped = true;
		}
		
//		poseY += mulsp(2f);
//		poseY += mulsp(1f);
	}
	public void attack(char[] type){
		double rad = (-90.0 + (rand.nextFloat(20)-10.0))/180.0*PI;
		Vector3 v = new Vector3(cos(rad) ,sin(rad) ,0.0f);//new Vector3(cos(rad)*6.0f ,-4.0f ,0.0f);//sin(rad)*6.0f,0.0f);;
		
		new Enemy2acc(rpos ,v ,2);
		
		
	}
	
}
public class EnemyE:Enemy{
	
	public:
	Vector3 vel;
//	Vector3 acc;
	
	
	
	public this(Vector3 pos ,Vector3 vel ){
		super(10 ,pos);
		this.vel = cast(Vector3)vel.clone();
//		if(o is null || !is(o == Vector3))this.acc = cast(Vector3)vel.clone() * -0.01f;
//		else this.acc = cast(Vector3)(cast(Vector3)o).clone();
//		this.acc = (cast(Vector3)vel.clone()) * -0.01f;
		
		shape = Octahedron.getShape();
		size = 30.0f;
		collisionRange = 15.0f;
//		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
		setFlyColor();
	}
	public void move(){
		super.move();
		if(cnt == divsp(45))attack("a");
		
		pos += mulsp(vel);
//		vel.y *= 0.98;//mulsp(acc.x);
		
		poseX += mulsp(2f);
		poseY += mulsp(1f);
	}
	public void attack(char[] type){

		Vector3 v = vec3Normalize(ship.rpos-rpos);
		for(double y=0.0;y<50.0f;y+=20.0f){
			new Enemy2(rpos+v*y ,v*3.0f ,2 );
		}
		
	}
	
}
public class EnemyF:Enemy{
	
	public:
	Vector3 vel;
	Vector3 acc;
	
	
	
	public this(Vector3 pos ,Vector3 vel ,Object o){
		super(6 ,pos);
		this.vel = cast(Vector3)vel.clone();
		if(o is null || !is(o == Vector3))this.acc = new Vector3();//new Vector3(0.0f,vel.y / -60.0f,0.0f);
		else this.acc = cast(Vector3)(cast(Vector3)o).clone();
//		this.acc = (cast(Vector3)vel.clone()) * -0.01f;
		
		shape = Octahedron.getShape();
		size = 30.0f;
		collisionRange = 15.0f;
//		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		
		setFlyColor();
	}
	public void move(){
		super.move();
		if(cnt == divsp(60))attack("a");
		
		pos += mulsp(vel);
		vel += mulsp(acc);
//		vel.y *= 0.98;//mulsp(acc.x);
		
		poseX += mulsp(2f);
		poseY += mulsp(1f);
	}
	public void attack(char[] type){

		new AccBullet(rpos ,new Vector3(),vec3Normalize(ship.rpos - rpos) * 0.05f);
		
	}
	
}


public class Mine:Enemy{
	public:
	Vector3 vel;
	static Shape sshape;
	static  float[][] a = 
		[
			[-1.2 , -0.4 ,0.0 ,0.4 ,1.2],
			[-1.2 , -0.4 ,0.0 ,0.4 ,1.2]
  	   ];
  	static float[][] b =
		[
			[0.0 , 0.4 ,1.2  ,0.4 ,0.0],
			[0.0 , 0.4 ,0.6  ,0.4 ,0.0]
  	];
	
	public this(Vector3 pos ,Vector3 vel){
		super(10 ,pos);
		this.vel = cast(Vector3)vel.clone();
		
		shape = getShape();
		size = 40.0f;
		collisionRange = 20.0f;
		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		poseY = -120.0;
		
		setFlyColor();
	}
	public void move(){
		super.move();
		/*
		if(cnt  == divsp(120)){
			attack("a");
			destroy();
		}
		*/
		
//		size = 20.0f + 30.0f * sin(cast(float)cnt / cast(float)divsp(120)*PI/2.0);
		pos += mulsp(vel);
		
		poseZ += mulsp(2f);
//		poseY += mulsp(1f);
	}
	public void destroy(){
		super.destroy();
		attack("a");
	}
	public void attack(char[] type){
		new AccBullet(rpos ,new Vector3(0.0f ,0.0f ,0.0f),new Vector3(0.0f,-0.1f,0.0f));
	}
	
	protected static Shape setShape(){
		return  new SH_Pole(a ,b ,8);//Cube.getShape();
	}
	public static Shape getShape(){
		if(sshape is null)sshape = setShape();
		return cast(Shape)sshape.clone();
	}
}
public class MiddleEnemy:Enemy{
	public:
	Vector3 vel;
	static Shape sshape;
	static float[][] a = [
	[0 ,0.2 ,0   ,-1.0 ,0.8 ,1.0 ,0.9 ,0.7],
	[0 ,0.2 ,0.2 ,0.2  ,0.5 ,0.5 ,0.5 ,0.0]
	
	
	
	];
	static float[][] b = [
	[0  ,0.4 ,0.8 ,1.2  ,1.0 ,0.6 ,0.2 ,0.0],
	[0  ,0.3  ,0.5 ,0.6 ,0.5 ,0.5 ,0.3 ,0.0]
	];
	public this(Vector3 pos ,Vector3 vel){
		super(20 ,pos);
		this.vel = cast(Vector3)vel.clone();
		
		shape = getShape();
		size = 50.0f;
		collisionRange = 25.0f;
		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		poseY = -120.0;
		
		setMiddleColor();
	}
	public void move(){
		super.move();
		if(cnt  % divsp(20) == 0 && cnt < divsp(80)){
			attack("a");
		}
		
		pos += mulsp(vel);
		
		poseX += mulsp(2f);
//		poseY += mulsp(1f);
	}
	public void attack(char[] type){
		Vector3 v;//vec3Normalize(ship.rpos -rpos) * 1.0f;
		for(double rad=-PI/2.0-PI/12.0;rad<=-PI/2.0+PI/11.0;rad+=PI/12.0){
			v = new Vector3(cos(rad) ,sin(rad) ,0.0f)*2.0f;
			new Enemy1(rpos ,v);
		}
	}
	protected static Shape setShape(){
		return  new SH_Pole(a ,b ,8);//Cube.getShape();
	}
	public static Shape getShape(){
		if(sshape is null)sshape = setShape();
		return cast(Shape)sshape.clone();
	}
}

public Shape LASERENEMYSHAPE;
public class LaserEnemy:Enemy{
	public:
	Vector3 vel;
	public this(Vector3 pos ,Vector3 vel){
		super(30 ,pos);
		this.vel = cast(Vector3)vel.clone();
		
		if(LASERENEMYSHAPE is null){
			Shape shape1 = OctaShape.getShape(0.5 ,1.0).translate(0.5f,0.0f,0.0f);
			Shape shape2 = OctaShape.getShape(0.5 ,1.0).translate(-0.5f,0.0f,0.0f);
			LASERENEMYSHAPE = shape2 + shape1;// + shape2;
		}
		shape = cast(Shape)LASERENEMYSHAPE.clone();
		
		size = 50.0f;
		collisionRange = 25.0f;
		poseZ = atan2(vel.y,vel.x)*180.0/PI;
		poseY = -120.0;
		
//		Parts p = new LaserImpl(new Vector3(0,0,0));
//		addChild(p ,"laser",size ,ENGAGED);
		Parts p = new LaserImpl(20);
		addChild(p ,"laser",size ,ENGAGED);
		
		setMiddleColor();
	}
	public void move(){
		super.move();
		if(cnt  % divsp(3) == 0){
			attack("a");
			
		}
		
		pos += mulsp(vel);
		
		poseX += mulsp(2f);
		linkZ += mulsp(2f);
		
//		poseY += mulsp(1f);
	}
	public void attack(char[] type){
		double rad;
		if(rpos.x<0)rad = -cast(double)cnt /720.0 * PI;
		else rad = PI + cast(double)cnt /720.0 * PI;
		new Enemy2(rpos ,new Vector3(cos(rad)*8.0f,sin(rad)*8.0f,0.0f),1 ,20);
	}
	
}

public Shape WALLENEMYSHAPE;
public class WallEnemy:Enemy{
	public:
	Vector3 vel;
	public this(Vector3 pos ,Vector3 vel){
		super(10 ,pos);
		this.vel = cast(Vector3)vel.clone();
		
		if(WALLENEMYSHAPE is null){
			WALLENEMYSHAPE = new SH_Sphere(8);
		}
		shape = cast(Shape)WALLENEMYSHAPE.clone();
		
		size = 40.0f;
		collisionRange = 20.0f;
		poseZ = atan2(vel.y,vel.x)*180.0/PI;
//		poseY = -120.0;
		
		setFlyColor();
		
		Parts e;
		for(float x = rpos.x-60;-250.0f<x;x-= 50.0f){
			e = new EnemyAppend(Cube.getShape() ,30.0f ,-1.0f ,0.9f,0.9f,0.9f,1.0f,false ,1);
			addChild(e ,"" ,0.0f ,LOCATION);
			e.pos.x = x-rpos.x;
		}
		for(float x = rpos.x+60;x<250.0f;x+= 50.0f){
			e = new EnemyAppend(Cube.getShape() ,30.0f ,-1.0f ,0.9f,0.9f,0.9f,1.0f,false ,1);
			addChild(e ,"" ,0.0f ,LOCATION);
			e.pos.x = x-rpos.x;
		}
		
		
	}
	public void move(){
		super.move();
		if(rpos.y < 0)pos += mulsp(vel/2.0);
		else pos += mulsp(vel*(rpos.y+screen.GAME_UP)/(screen.GAME_UP*2.0));
		
		poseZ += mulsp(2f);
		
//		poseY += mulsp(1f);
	}
	public void attack(char[] type){
		
	}
	
}

