#include "empire.h"
#include "logic.h"

vector<_loc> find_attackables(_unit *u)
{  //locates all possible units that this unit could attack (including units that a direct attacker could move to and then attack)
	vector<_loc> attackables;
	
	if (u->attackdelay > 0)
		return attackables;
	
	if (unitstats[u->type].attacktype == DIRECT)
	{
		bool arange[MAP_MAX_L][MAP_MAX_H];
		
		int movement = u->move;
		if (!u->canmove) movement = 0;  //if it can't move, it can only attack adjacent tiles
		
		memset(arange, 0, MAP_MAX_L * MAP_MAX_H);  //fill the range with 'false'
		
		//this assumes the unit has a pathmap already created for it
		//if this function is ever called outside of unit_selected(), that may cause trouble
		for (int y = 0; y < worldmap.get_height(); y++)
		{
			for (int x = 0; x < worldmap.get_length(); x++)
			{
				if (worldmap.get_tile(x, y)->get_step() <= movement)
				{
					if ((any_unit_here(x, y) == -1) || (any_unit_here(x, y) == u->owner * 100 + u->number))
					{
						if (x > 0)
						{
							arange[x - 1][y] = true;
						}
						if (x < worldmap.get_length() - 1)
						{
							arange[x + 1][y] = true;
						}
						if (y > 0)
						{
							arange[x][y - 1] = true;
						}
						if (y < worldmap.get_height() - 1)
						{
							arange[x][y + 1] = true;
						}
					}
				}
			}
		}

		for (int y = 0; y < worldmap.get_height(); y++)
		{
			for (int x = 0; x < worldmap.get_length(); x++)
			{
				if (arange[x][y])
				{
					_unit *tileunit = worldmap.get_tile(x, y)->unit_here_ptr();
					
					if ((tileunit != 0) && (tileunit->owner != u->owner) && (type_can_attack(u, tileunit)))
						attackables.push_back(_loc(x, y));
				}
			}
		}
	}
	else if (unitstats[u->type].attacktype == RANGED)
	{  //search for attackable units anywhere within range
		int max, min, y, x;
		
		max = u->rangemax;
		min = u->rangemin;
		y = u->tiley - max;
		if (y < 0) y = 0;
		while ((y <= u->tiley + max) && (y < worldmap.get_height()))
		{
			x = u->tilex - max;
			if (x < 0) x = 0;
			while ((x <= u->tilex + max) && (x < worldmap.get_length()))
			{
				int i = tile_distance(x, y, u->tilex, u->tiley);
				if ((i >= min) && (i <= max))
				{
					if (attackable_unit_here(u, x, y, true) != -1)
					{
						attackables.push_back(_loc(x, y));
					}
				}
				x++;
			}
			y++;
		}
	}
	
	return attackables;
}

void draw_attackables(vector<_loc> locations)
{
	static int r = 0;
	int i, m, t1, t2, u;
	int d = MAP_TILE_SIZE;
	r += 3;
	if (r > 256)
	{
		r -= 256;
	}
	i = 0;
	m = locations.size();
	while (i < m)
	{  //rotates a targeting thingy over each attackable enemy
		t1 = (locations[i].x - worldmap.camera.get_scroll_x()) * MAP_TILE_SIZE + worldmap.camera.get_offset_x();
		t2 = (locations[i].y - worldmap.camera.get_scroll_y()) * MAP_TILE_SIZE + worldmap.camera.get_offset_y();
		u = worldmap.get_tile(locations[i].x, locations[i].y)->unit_here();
		if (player[u / 100].team == player[game->pturn].team)
		{  //if this attackable unit is on an allied team
			buffer_hline(t1, t2, t1 + 10, GREEN, 0.9);
			buffer_hline(t1, t2 + 1, t1 + 10, GREEN, 0.9);
			buffer_hline(t1 + (d - 11), t2, t1 + (d - 1), GREEN, 0.9);
			buffer_hline(t1 + (d - 11), t2 + 1, t1 + (d - 1), GREEN, 0.9);
			buffer_hline(t1, t2 + (d - 2), t1 + 10, GREEN, 0.9);
			buffer_hline(t1, t2 + (d - 1), t1 + 10, GREEN, 0.9);
			buffer_hline(t1 + (d - 11), t2 + (d - 2), t1 + (d - 1), GREEN, 0.9);
			buffer_hline(t1 + (d - 11), t2 + (d - 1), t1 + (d - 1), GREEN, 0.9);
			buffer_vline(t1, t2, t2 + 10, GREEN, 0.9);
			buffer_vline(t1 + 1, t2, t2 + 10, GREEN, 0.9);
			buffer_vline(t1 + (d - 2), t2, t2 + 10, GREEN, 0.9);
			buffer_vline(t1 + (d - 1), t2, t2 + 10, GREEN, 0.9);
			buffer_vline(t1, t2 + (d - 11), t2 + (d - 1), GREEN, 0.9);
			buffer_vline(t1 + 1, t2 + (d - 11), t2 + (d - 1), GREEN, 0.9);
			buffer_vline(t1 + (d - 2), t2 + (d - 11), t2 + (d - 1), GREEN, 0.9);
			buffer_vline(t1 + (d - 1), t2 + (d - 11), t2 + (d - 1), GREEN, 0.9);
		}  //(draws a green square-like target thingy)
		else
		{
			buffer_rotate_sprite(glb.bmp(12), t1 + MAP_TILE_SIZE / 2, t2 + MAP_TILE_SIZE / 2, r);
		}
		i++;
	}
}

int attackable_unit_here(_unit *attacker, int tx, int ty)
{
  return attackable_unit_here(attacker, tx, ty, false);
}

int attackable_unit_here(_unit *attacker, int tx, int ty, bool ignore_teams)
{
	int u, d;
	_unit *defender;
	const _tile *t = worldmap.get_tile(tx, ty);

	if (t == 0)
		return -1;

	u = t->unit_here();

	if (attacker->attackdelay > 0) return -1;

	if ((u != -1) && (u / 100 != attacker->owner))
	{
		defender = &player[u / 100].unit[u % 100];
		if (player[attacker->owner].team == player[defender->owner].team)
		{  //if the players are on the same team
			if (!ignore_teams)
			{  //if teams are being recognized
				return -1;
			}
		}
		if (type_can_attack(attacker, defender))
		{  //if the attacker could, in theory, attack the defender
			d = tile_distance(attacker->tilex, attacker->tiley, tx, ty);
			if (unitstats[attacker->type].attacktype == DIRECT)
			{  //if the attacker is direct and next to the defender, it can attack
				if (d == 1)
				{
					return u;
				}
			}
			else if (unitstats[attacker->type].attacktype == RANGED)
			{
				if ((d >= attacker->rangemin) && (d <= attacker->rangemax))
				{  //if the attacker has the defender within its firing range, it can attack
					return u;
				}
			}
		}
	}
	return -1;
}

bool type_can_attack(_unit *a, _unit *d)
{
	const short land = 1;
	const short air  = 2;
	const short sea  = 4;

	if (a->attackdelay > 0) return false;

	short c = unitstats[a->type].canhit;

	switch(unitstats[d->type].basetype)
	{
		case LAND:
			if (c & land) return true;
			break;
		case AIR:
			if (c & air) return true;
			break;
		case SEA:
			if (c & sea) return true;
			break;
	}
	return false;
}
