
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

#include <allegro.h>
#include <winalleg.h>

#include <vector>
#include <string>
#include <algorithm>

using namespace std;



#define DIFFICULTY		10
#define HIVE_HP			1000



class tUnit {
public:
	float	xp,yp;
	float	vx,vy;
	float	tx,ty;
	bool	selected;
	bool	hive;
	int		side;
	int		enemy;
	float	timer;
	int		hp;
	
	tUnit() : selected(false),enemy(-1), timer(0), vx(0), vy(0), hive(false), hp(100) {}

	void Draw(BITMAP *buff);
	bool Think(float delta);
	void MoveTo(float x2,float y2);
};


vector<tUnit> units[2];
int sel_cx,sel_cy;
float sel_rad;
int _mb=0;
float closest_dist;


int nearest_unit(int side,float xp,float yp)
{
	float md2=100000;
	int id = -1;
	for(int i=0;i<units[side].size();i++)
	{
		float dx = units[side][i].xp - xp;
		float dy = units[side][i].yp - yp;
		dx=dx*dx+dy*dy;
		if(units[side][i].hive)
			dx/=9;
		if(md2>dx)
		{
			md2=dx;
			id=i;
		}
	}
	closest_dist = sqrt(md2);
	return id;
}



void tUnit::Draw(BITMAP *buff)
{
	int col = 2;
	if(selected) col=14;
	if(side!=0) col=4;
	circle(buff,int(xp),int(yp),hive?int(13-timer*2):2,col);
	if(hive)
	{
		hline(buff,int(xp)-6,int(yp),int(xp)+6,8);
		hline(buff,int(xp)-6,int(yp),int(xp)-6+int((13.f*hp)/HIVE_HP),col);
	}
}

bool tUnit::Think(float delta)
{
	if(hp<=0)
		return false;

	if(hive)
	{
		selected = false;
		timer-=delta;
		if(timer<=0)
		{
			hp+=10;
			if(hp>HIVE_HP)
				hp=HIVE_HP;

			float r = (rand()%360)*M_PI/180.f;
			tUnit u;

			u.side = side;
			u.xp = xp;
			u.yp = yp;
			u.tx = xp + cos(r)*30;
			u.ty = yp + sin(r)*30;

			units[side].push_back(u);

			timer+=1+(rand()%1000)/1000.f;
		}
		
		return true;
	}
	

	// AI
	timer-=delta;
	if(timer<=0)
	{
		int enemy = nearest_unit(!side,xp,yp);
		if(enemy>=0)
		{
			if(closest_dist<5)
				units[!side][enemy].hp-=rand()%120;
		
			if(side!=0 && (closest_dist<30 || (rand()%100<DIFFICULTY)))
			{
				tx = units[!side][enemy].xp;
				ty = units[!side][enemy].yp;
			}

			timer+=0.5+(rand()%500)/1000.f;
		}
	}

	float acc = 0.3;
	float frc = 0.5;

	acc = acc*delta;
	frc = pow(frc,delta);

	vx+=(tx-xp)*acc;	vx*=frc;
	vy+=(ty-yp)*acc;	vy*=frc;
	xp+=vx*delta;
	yp+=vy*delta;

	return true;
}

void tUnit::MoveTo(float x2,float y2)
{
	tx=x2+rand()%21-10;
	ty=y2+rand()%21-10;
}



void init_armies()
{
	for(int s=0;s<2;s++)
	{
		units[s].clear();
		for(int y=0;y<3;y++)
		{
			tUnit u;

			u.side = s;
			u.xp = 40+560*s;
			u.yp = 40+200*y;
			u.hive = true;
			u.hp = HIVE_HP;

			units[s].push_back(u);
		}
	}
}


void think_mouse()
{
	int mx = mouse_x;
	int my = mouse_y;
	int mb = mouse_b;
	if(mb&2) mb=2;
	
	if(mb==1 && _mb!=1)
	{
		sel_cx = mx;
		sel_cy = my;
		sel_rad=0;
	}
	
	if(mb==1)
	{
		int dx=mx-sel_cx;
		int dy=my-sel_cy;
		sel_rad=sqrt(float(dx*dx+dy*dy));
	}
	
	if(mb!=1 && _mb==1)
		for(int i=0;i<units[0].size();i++)
		{
			int dx=units[0][i].xp-sel_cx;
			int dy=units[0][i].yp-sel_cy;
			units[0][i].selected = (sqrt(float(dx*dx+dy*dy))<=sel_rad);
		}

	if(mb==2 && _mb!=2)
		for(int i=0;i<units[0].size();i++)
			if(units[0][i].selected)
				units[0][i].MoveTo(mx,my);

	_mb = mb;
}



int main()
{
	allegro_init();
	install_keyboard();
	install_timer();
	install_mouse();
	
	set_color_depth(8);
	set_gfx_mode(GFX_AUTODETECT_WINDOWED,640,480,0,0);

	show_mouse(screen);
	
	BITMAP *buff = create_bitmap(SCREEN_W,SCREEN_H);
	clear(buff);
	
	init_armies();

	unsigned int t0,t1;
	t0=t1=timeGetTime();

	while(!key[KEY_ESC])
	{
		clear(buff);
		
		for(int s=0;s<2;s++)
			for(int i=0;i<units[s].size();i++)
				units[s][i].Draw(buff);
			
		if(_mb==1)
			circle(buff,sel_cx,sel_cy,int(sel_rad),2);
		
		vsync();
		blit(buff,screen,0,0,0,0,SCREEN_W,SCREEN_H);

		t1 = timeGetTime();
		float delta = (t1-t0)/1000.f;
		t0=t1;
		
		think_mouse();

		for(int s=0;s<2;s++)
			for(int i=0;i<units[s].size();i++)
				if(!units[s][i].Think(delta))
				{
					units[s][i] = units[s][units[s].size()-1];
					units[s].erase(units[s].end()-1);
					i--;
				}

	}

	return 0;
}
END_OF_MAIN()

