/*


----------------------------- SANITY WARNING -----------------------------

	This class is a large, jumbled mess of hacks, principled code and magic numbers.
	The important thing to remember is that, for the most part, it fulfills its role of
	maintaining an army -- including mechanisms for maintaining spacial structure, finding and
	assaulting targets, and disbanding the army if it is no longer needed. It should be clear then
	that this large set of responsibilities results in a large and complex set of interacting sub-systems.


----------------------------- SANITY WARNING -----------------------------


*/


#include "Army.h"
#include "Overseer.h"
#include "ZealotGeneralMicroBehaviour.h"
#include "ArcingDragoonMicroBehaviour.h"
#include "ArbiterGeneralMicroBehaviour.h"
#include "SupportingObserverMicroBehaviour.h"
#include "ReaverShuttleMicroBehaviour.h"
#include "HighTemplarGeneralMicroBehaviour.h"
#include "ArchonGeneralMicroBehaviour.h"
//#include "Windows.h"
#include "Army.h"
#include "MapData.h"
Army::Army(Overseer* ov)
{
	formed = false;
	movingToTargetRegion = false;
	attackingTargetRegion = false;
	overseer = ov;
	armyIsReforming = false;
	armyUnderAttack = false;
	combat_just_switched = false;
	REFORM_WAIT_PERIOD = 32;
	reformFrameLimit = REFORM_WAIT_PERIOD;
	next_waypoint_is_choke = false;
	zealots_ahead = false;
	DEATH_THRESHOLD = 0.25;
	centrePoint = Positions::None;
	tickCount = 64;
	armyInTargetRegion = false;
	armyIdleCounter = 0;
	PATH_CALCULATION_LIMIT = 0;
	failedPathAttempts = 0;
	lastAttacker = NULL;
	isContain = false;
	combatAnchor = Positions::None;
	alive = true;
	supportSquad = false;
}

void Army::initialize()
{
	initialForceSize = members.size();

	if(initialForceSize < 10 && Broodwar->getFrameCount() < 15000 && !supportSquad) {

		isContain = true;

	}
	//setTarget(overseer->getUnitManager()->getBelievedEnemyMainBaseRegion());
	setTarget(findNewTarget());

	initialStateMap[UnitTypes::Protoss_Dragoon] = countNumTypeInArmy(UnitTypes::Protoss_Dragoon);
	initialStateMap[UnitTypes::Protoss_Zealot] = countNumTypeInArmy(UnitTypes::Protoss_Zealot);
	initialStateMap[UnitTypes::Protoss_Dark_Templar] = countNumTypeInArmy(UnitTypes::Protoss_Dark_Templar);
	initialStateMap[UnitTypes::Protoss_Archon] = countNumTypeInArmy(UnitTypes::Protoss_Archon);
	initialStateMap[UnitTypes::Protoss_Shuttle] = countNumTypeInArmy(UnitTypes::Protoss_Shuttle);
	initialStateMap[UnitTypes::Protoss_Reaver] = countNumTypeInArmy(UnitTypes::Protoss_Reaver);
	initialStateMap[UnitTypes::Protoss_High_Templar] = countNumTypeInArmy(UnitTypes::Protoss_High_Templar);

}

void Army::monitor()
{
	alive = checkAlive();
	if(!alive || members.empty()) {
		return;
	}
	if(target == NULL) {
		////OutputDebugString(TEXT("Target is null"));
		return;
	}
	if(PATH_CALCULATION_LIMIT > 0) {
		PATH_CALCULATION_LIMIT--;
	}

	if(target != NULL) {
		//Broodwar->drawCircleMap(target->getCenter().x(), target->getCenter().y(), 64, BWAPI::Colors::Red, true);

		if(isContain && Broodwar->getFrameCount() > 20000) {
			isContain = false;
			target = originalTarget;
			calculatePath();
			transformPath();
			formUp();
		}
	}


	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* c = *i;
		if(c->isAlive()) {
			//Broodwar->drawLineMap(centrePoint.x(), centrePoint.y(), c->getPosition().x(), c->getPosition().y(), BWAPI::Colors::Green);
		}
	}
	if(Broodwar->getFrameCount()%64 == 0) {
		BaseModel* bm = overseer->getUnitManager()->getEnemyBaseModelInRegion(curRegion);
		if(bm != NULL) {
			if(bm->isAlive()) {
				target = curRegion;
				overseer->getOffenseMonitor()->registerTarget(this, curRegion);
			}
		}
	}

	if(Broodwar->getFrameCount()%16==0){



		if(lastCentrePoint.getDistance(centrePoint) < 128 && !armyUnderAttack) {
			armyIdleCounter++;
			if(armyIdleCounter >= 32 && !armyInTargetRegion && PATH_CALCULATION_LIMIT == 0) {
				////Broodwar->sendText("--------------------- recovering army");


				//	centrePoint = BWTA::getNearestChokepoint(centrePoint)->getCenter();
				calculatePath();
				transformPath();
				formUp();
				armyIdleCounter = 0;
				return;
			}
		}
	}

//	clearChokePointObstructions();

	if(Broodwar->getFrameCount()%128 == 0) {
		manageGroundReplacementRequests();
		manageAirReplacementRequests();
	}

	if(Broodwar->getFrameCount()%6 == 0) {
		bool needsToReform = false;
		bool oldValue = armyUnderAttack;
		if(BWTA::getNearestChokepoint(centrePoint)->getCenter().getDistance(centrePoint) > 128) {
			if(target == BWTA::getRegion(centrePoint) && path.size() <= 10) {
				armyInTargetRegion = true;
			} else {
				armyInTargetRegion = false;
			}
			BaseModel* nearestBase = overseer->getUnitManager()->getBaseModelInRegion(curRegion);
			if(nearestBase != NULL) {
				if(nearestBase->isUnderThreat()) {
					armyInTargetRegion = true;
				}
			}
		}
		armyUnderAttack = isArmyUnderAttack();

		if(oldValue != armyUnderAttack) {
			combat_just_switched = true;
		}

		if(armyUnderAttack) {
			rallyIdleMembers();
			defendSelf();
		} else {
			if(armyInTargetRegion) {
				assaultRegion();
				return;
			} else {
				// hacking our way around a bug
				if(path.empty() && target != NULL && !localPathMap[(TilePosition)(target->getCenter())].empty()) {
					currentWayPoint = BWTA::getNearestChokepoint(target->getCenter())->getCenter();
				}
			}
		}

		if(combat_just_switched) {
			reform();
			if(armyUnderAttack) {
				combatAnchor = centrePoint;
			}
			if(!armyInTargetRegion && !armyUnderAttack) {

				if(centrePoint.getDistance(combatAnchor) >= 512) {
					calculatePath();
					transformPath();
				}

			}
			combat_just_switched = false;
		}
		if(armyUnderAttack) {
			return;
		}

	}	
	if(!armyUnderAttack) {
		manageIdleMap();

	}
	manageArmySpacialStructure();
}

void Army::setTarget( BWTA::Region* r )
{

	target = r;
	originalTarget = r;
	if(target == NULL) {
		////OutputDebugString(TEXT("NO IDEA WHERE TO GO"));
		target = curRegion;
		return;
	}

	////OutputDebugString(TEXT("SETTING TARGET"));

	if(isContain) {
		////OutputDebugString(TEXT("LAUNCHING CONTAIN"));

		std::set<BWTA::BaseLocation*> startLocs = BWTA::getStartLocations();
		bool foundLoc = false;
		for (std::set<BaseLocation*>::iterator i = startLocs.begin(); i != startLocs.end(); ++i)
		{
			if((*i)->getRegion() == originalTarget) {
				foundLoc = true;
				break;
			}
		}
		if(!foundLoc) {
			isContain = false;
		}
		if(foundLoc && isContain){
			std::set<BWTA::BaseLocation*> bases = BWTA::getBaseLocations();
			BWTA::BaseLocation* nearestBase = NULL;
			TilePosition bestLoc = TilePositions::None;
			for (std::set<BaseLocation*>::iterator i = bases.begin(); i != bases.end(); ++i)
			{
				BaseLocation* cur = *i;
				if(cur->getRegion() == target || cur->getRegion()->getBaseLocations().empty()) {
					continue;
				}
				if(nearestBase == NULL) {
					nearestBase = cur;
					bestLoc = nearestBase->getTilePosition();
				} else {
					TilePosition startLoc = (TilePosition)target->getCenter();
					TilePosition curLoc = (TilePosition)cur->getRegion()->getCenter();

					int distance = BWTA::getGroundDistance(startLoc, curLoc);
					int bestDistance = BWTA::getGroundDistance(startLoc, bestLoc);
					if(distance < bestDistance && distance > 5) {
						nearestBase = cur;
						bestLoc = (TilePosition)cur->getRegion()->getCenter();
					}
				}
			}
			if(nearestBase != NULL) {
				target = nearestBase->getRegion();
			}
		}
	}

	int avgX = 0;
	int avgY = 0;
	int livingMembers = 0;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}	
		//if(cur->getPosition().getDistance(overseer->getUnitManager()->getFriendlyMainBase()->getPosition()) < 1024) {
		if(cur->getType() != UnitTypes::Protoss_Shuttle && cur->getType() != UnitTypes::Protoss_Observer && !cur->getUnit()->isLoaded()) {
			if(unitIsInTargetRegion(cur) && !armyInTargetRegion) {
				continue;
			}


			avgX = avgX+cur->getPosition().x();
			avgY = avgY+cur->getPosition().y();
			livingMembers++;

		}
		//}
	}

	if(members.size() == 1) {
		centrePoint = members.at(0)->getPosition();
	} else {
		lastCentrePoint = centrePoint;
		if(livingMembers != 0) {
			centrePoint = Position(avgX/livingMembers, avgY/livingMembers);
		}
		
	}
	overseer->getOffenseMonitor()->registerTarget(this, target);
	origin = overseer->getUnitManager()->getClosestFriendlyBaseModel(centrePoint)->getBaseLOC()->getTilePosition();
	calculatePath();
	transformPath();
}

void Army::addToArmy( UnitModel* u )
{
	if(u->getArmyOwner() != NULL){
		return;
	}
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = (*i);
		if(u == cur) {
			return;
		}
	}

	if(u->getType() == UnitTypes::Protoss_Arbiter) {
		//////Broodwar->sendText("attached army to arbiter");
		ArbiterGeneralMicroBehaviour* a = (ArbiterGeneralMicroBehaviour*) u->getMicroBehaviour();
		a->setTargetArmy(this);
	}
	if(u->getType() == UnitTypes::Protoss_Observer) {
		//////Broodwar->sendText("attached army to observer");
		SupportingObserverMicroBehaviour* s = new SupportingObserverMicroBehaviour(u, overseer->getUnitManager());
		s->setTargetArmy(this);
		u->setMicroBehaviour(s);
	}
	if(u->getType() == UnitTypes::Protoss_Shuttle) {
		////Broodwar->sendText("attached army to shuttle");
		ReaverShuttleMicroBehaviour* s = new ReaverShuttleMicroBehaviour(u, overseer->getUnitManager());
		s->setTargetArmy(this); // can probably get rid of this now
		u->setArmyOwner(this);
		u->setMicroBehaviour(s);
	}
	if(u->getType() == UnitTypes::Protoss_Zealot) {
		u->setArmyOwner(this);
	}
	if(u->getType() == UnitTypes::Protoss_High_Templar) {
		u->setArmyOwner(this);

	}
	if(u->getType() == UnitTypes::Protoss_Archon) {
		u->setArmyOwner(this);
	}
	if(u->getType() == UnitTypes::Protoss_Dark_Templar) {
		ZealotGeneralMicroBehaviour* zm = new ZealotGeneralMicroBehaviour(u, overseer->getUnitManager());
		u->setMicroBehaviour(zm);
		u->setArmyOwner(this);
	}
	u->setArmyOwner(this);
	members.push_back(u);
	idleMap.insert(pair<UnitModel*,int>(u, 0));
}

void Army::formUp()
{
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		if((*i)->getUnit()->isAttackFrame() || (*i)->getUnit()->isAttacking() || (*i)->getUnit()->isStartingAttack()) {
			continue;
		}
		(*i)->getUnit()->move(currentWayPoint);
		(*i)->setCurrentTaskType(ATTACK);
	}
}

void Army::attackTargetRegion()
{
	//reform();
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		cur->getUnit()->move(target->getCenter());
	}
}

void Army::reform()
{

	armyIsReforming = true;
	if(armyFront.size() < members.size() || armyBack.size() < members.size()) {
		return;
	}	
	UnitModel* furthestAway = NULL;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive() || cur->getUnit()->getOrder() == BWAPI::Orders::CastPsionicStorm || cur->getUnit()->isStartingAttack()) {
			continue;
		}
		if(furthestAway == NULL) {
			furthestAway = cur;
		} else {
			if(furthestAway->getPosition().getDistance(centrePoint) < cur->getPosition().getDistance(centrePoint)) {
				furthestAway = cur;
			}
		}
		if(cur->getPosition().getDistance(centrePoint) < furthestDistance*0.8) {
			cur->getUnit()->stop();
			continue;
		}
		if(cur->isFollowingPath()) {
			cur->pathStop();
		}
		if(cur->getType() == UnitTypes::Protoss_Dragoon) {
			Position closest = cur->findClosestPoint(armyBack, centrePoint, furthestDistance);
			cur->getUnit()->move(closest);
		}
		if(cur->getType() == UnitTypes::Protoss_Shuttle) {
			Position closest = cur->findClosestPoint(armyBack, centrePoint, furthestDistance);
			cur->getUnit()->move(closest);
		}
		if(cur->getType() == UnitTypes::Protoss_Zealot || cur->getType()==UnitTypes::Protoss_Archon || cur->getType() == UnitTypes::Protoss_Dark_Templar) {
			Position closest = cur->findClosestPoint(armyFront, centrePoint, furthestDistance);
			cur->getUnit()->move(closest);
		}
		if(cur->getType() == UnitTypes::Protoss_Reaver) {
			Position closest = cur->findClosestPoint(armyBack, centrePoint, furthestDistance);
			cur->getUnit()->move(closest);
		}
	}
}

vector<UnitModel*> Army::getMembers()
{
	return members;
}

void Army::calculateArmyStructure()
{
	armyFront.clear();
	armyBack.clear();
	if(members.empty()) {
		return;
	}

	std::set<BWTA::Region*> r = target->getReachableRegions();
	if(r.empty()) {
		return;
	}
	// look through all the reachable regions
	// see if we are in one
	effectiveTarget = target->getCenter();

	bool inRegion = false;
	curRegion = BWTA::getRegion(centrePoint);

	if(curRegion == NULL || target == NULL) {
		return;
	}
	if(curRegion != target) {
		for (std::set<BWTA::Region*>::iterator i = r.begin(); i != r.end(); ++i)
		{
			BWTA::Region* cur = *i;
			if(curRegion == cur) {
				// so our army is in the region of our target
				inRegion = true;
				next_waypoint_is_choke = false;
				break;
			} else {
				// we are NOT in the region of our target
			}
		}

		std::set<BWTA::Chokepoint*> c = curRegion->getChokepoints();
		if(c.empty()) {
			return;
		}
		Chokepoint* bestCP = NULL;
		for (std::set<BWTA::Chokepoint*>::iterator it = c.begin(); it != c.end(); ++it)
		{
			Chokepoint* cur = *it;
			if(bestCP == NULL ) {
				bestCP = cur;
			} else {
				if(cur->getCenter().getApproxDistance(target->getCenter()) < bestCP->getCenter().getApproxDistance(target->getCenter())) {
					bestCP = cur;
				}
			}
		}
		effectiveTarget = bestCP->getCenter();
		next_waypoint_is_choke = true;
	}
	if(effectiveTarget == NULL) {
		return;
	}

	//Broodwar->drawLineMap(centrePoint.x(), centrePoint.y(), effectiveTarget.x(), effectiveTarget.y(), BWAPI::Colors::White);
	//Broodwar->drawLineMap(centrePoint.x(), centrePoint.y(), target->getCenter().x(),  target->getCenter().y(), BWAPI::Colors::Red);

}

void Army::nextWayPoint()
{
	bool anyOutOfPlace = false;


	// new version
	if(currentWayPoint.getDistance(centrePoint) <= 194+(members.size()*1.5)) {
		anyOutOfPlace = false;
	} else {
		anyOutOfPlace = true;
	}


	if(!anyOutOfPlace) {
		//A////Broodwar->sendText("all in order");
		bool canPop = false;
		if(BWTA::getRegion(centrePoint) == BWTA::getRegion(currentWayPoint) || centrePoint.getApproxDistance(currentWayPoint) < 128) {
			canPop = true;
		}

		if(canPop) {
		if(!path.empty() && path.begin() != path.end()) {
			path.erase(path.begin());
			if(!path.empty() && path.begin() != path.end()) {
				currentWayPoint = (Position)(*(path.begin()));
			}
		}
		}
	} else {
		//d////Broodwar->sendText("a guy is out of place!");
	}
}

void Army::calculatePath()
{

	///	path = BWTA::getShortestPath((TilePosition)(centrePoint.makeValid()), (TilePosition)(target->getCenter()));
	if(PATH_CALCULATION_LIMIT != 0) {
		return;
	}

	// look to see if we already have a path
	BWTA::Region* start = BWTA::getRegion(origin);
	BWTA::Region* end = BWTA::getRegion(target->getCenter());

	bool hasRepoPath = overseer->getUnitManager()->getPathRepo()->hasPathGround(start, end);
	bool isReusingPath = false;
	if(!localPathMap[(TilePosition)(target->getCenter())].empty() || hasRepoPath) {
		////OutputDebugString(TEXT("REUSING LOCAL PLAN\n"));
		std::vector<TilePosition> temppath;
		isReusingPath = true;
		if(!localPathMap[(TilePosition)(target->getCenter())].empty()) {
			temppath = localPathMap[(TilePosition)(target->getCenter())];
			//Broodwar->sendText("using local path");
		} else {
		if(hasRepoPath) {
			temppath = overseer->getUnitManager()->getPathRepo()->getPathGround(start, end);
			localPathMap[(TilePosition)(target->getCenter())] = temppath;
			//Broodwar->sendText("using repo path");
			}
		}
		
		TilePosition best = TilePositions::None;
		for(std::vector<TilePosition>::const_iterator i = temppath.begin(); i != temppath.end(); i++) {
			TilePosition ct = *i;
			TilePosition centre = (TilePosition)centrePoint;
			if(BWTA::getRegion(ct) != BWTA::getRegion(centre)) {
				continue;
			}
			if(best == TilePositions::None) {
				best = ct;
			} else {
				int distToCent = ct.getDistance(centre);
				int bestDist = best.getDistance(centre);
				if(distToCent < bestDist) {
					best = ct;
				}
			}
		}
		bool loading = false;
		bool ignoreLocal = true;
		path.clear();
		for(std::vector<TilePosition>::const_iterator it = temppath.begin(); it != temppath.end(); it++) {
			TilePosition ctt = *it;
			if(!loading) {
			if(ctt == best) {
				loading = true;
			} else {
				continue;
			}
			}

			if(loading) {

				if(ignoreLocal) {
				BaseModel* bm = overseer->getUnitManager()->getBaseModelInRegion(BWTA::getRegion(ctt));
					if(bm != NULL && bm->isFriendlyBase()){

					} else {
						ignoreLocal = true;
						path.push_back(ctt);
					}
				} else {
					path.push_back(ctt);
				}

			}
		}

		if(path.empty() || path.begin() == path.end()) {
			failedPathAttempts = 3;
			reformFrameLimit = REFORM_WAIT_PERIOD+1;
			return; 
		}
		currentWayPoint = (BWAPI::Position)(*(path.begin()));
		reformFrameLimit = REFORM_WAIT_PERIOD+1;
		failedPathAttempts = 0;
		return;
	} else {
			
	path.clear();
	int grain = 1;

	path = overseer->getUnitManager()->AstarSearchPathNoObstacles((TilePosition)start->getCenter(), (TilePosition)(target->getCenter()),grain);
	
	//Broodwar->sendText("calculating new path");
	badPath = path;
	if(path.begin() == path.end() || path.empty() || path.size() <= 3) {
		failedPathAttempts++;


		if(path.begin() == path.end()) {
			////OutputDebugString(TEXT("begin == end"));
		}
		if(path.empty()) {
			////OutputDebugString(TEXT("empty path"));
		}
		if(failedPathAttempts >= 2) {
			currentWayPoint = BWTA::getNearestChokepoint(target->getCenter())->getCenter();

		} else {
			currentWayPoint = centrePoint;
		}
		return;
	}

	failedPathAttempts = 0;
	currentWayPoint = (BWAPI::Position)(*(path.begin()));
	reformFrameLimit = REFORM_WAIT_PERIOD+1;
	localPathMap[(TilePosition)(target->getCenter())] = path;
	overseer->getUnitManager()->getPathRepo()->registerPathGround(start, end, path);


	}
}

void Army::transformPath()
{

	if(members.empty()) {
		return;
	}
	UnitModel* referenceMember = NULL;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		if(!(*i)->getType().isFlyer()) {
			referenceMember = (*i);
			break;
		}
	}
	if(referenceMember == NULL){
		return;
	}
	if(PATH_CALCULATION_LIMIT != 0) {
		return;
	}
	std::vector<TilePosition> newPath;
	TilePosition ref = (TilePosition)overseer->getUnitManager()->getFriendlyMainBase()->getPosition();
	for (std::vector<TilePosition>::iterator i = path.begin(); i != path.end(); ++i)
	{
		Position cur = (Position)(*i);	
	if(overseer->getUnitManager()->isRegionOwnedByMe(BWTA::getRegion(cur))) {
			continue;
		}
		ParticleGenerator* p = new ParticleGenerator(64,128,cur);
		std::vector<Position> v = p->generate();
		int innerScore = 0;

		BWTA::Region* origin = BWTA::getRegion(cur);
		// establish score for this path chunk
		ParticleGenerator* pvv = new ParticleGenerator(64,128,cur);
		std::vector<Position> vvv = pvv->generate();
		int curScore = 0;
		for (std::vector<Position>::iterator ittt = vvv.begin(); ittt != vvv.end(); ++ittt)
		{
			Position mCur = *ittt;
			if(MapData::walkability[mCur.x()/8, mCur.y()/8] && ref.hasPath((TilePosition)mCur)) {
				innerScore++;
			}else {
				innerScore--;
			}
		}
		int outerScore = 0;
		Position bestReplacement = cur;

		// children
		for (std::vector<Position>::iterator it = v.begin(); it != v.end(); ++it)
		{
			Position nCur = *it;
			ParticleGenerator* pv = new ParticleGenerator(64,128,nCur);
			std::vector<Position> vv = pv->generate();
			int chScore = 0;

			// scoring children
			for (std::vector<Position>::iterator itt = vv.begin(); itt != vv.end(); ++itt)
			{
				Position mCur = *itt;
				//TilePosition mct = (TilePosition)mCur;
				if(MapData::walkability[mCur.x()/8, mCur.y()/8] && ref.hasPath((TilePosition)mCur)) {
					chScore++;
				} else {
					chScore--;
				}

			}
			if(chScore > innerScore && BWTA::getRegion(nCur) == origin) {	
				innerScore = chScore;
				bestReplacement = nCur;
			}
		}
		newPath.push_back((TilePosition)bestReplacement);
	}
	path.clear();
	path = newPath;
	PATH_CALCULATION_LIMIT = 32;
}

void Army::manageArmySpacialStructure()
{
	// radius will be the magnitude of difference
	// so get the centre position
	// then find the guy who is furthest away from it. the distance is our radius
	int avgX = 0;
	int avgY = 0;
	int livingMembers = 0;
	if(BWTA::getNearestChokepoint(currentWayPoint)->getCenter().getDistance(currentWayPoint) < 64) {

	} else {
		curRegTar = BWTA::getRegion(currentWayPoint);
	}
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}		
		if(cur->getType() == UnitTypes::Protoss_Shuttle || cur->getType() == UnitTypes::Protoss_Observer ||  cur->getUnit()->isLoaded()) {

		} else {

			if(cur->getPosition().getDistance(centrePoint) < 768) {
				avgX = avgX+cur->getPosition().x();
				avgY = avgY+cur->getPosition().y();
				livingMembers++;
			}
		}

		if(cur->getUnit()->isStartingAttack() || cur->getUnit()->isAttacking()) {
			continue;
		}		
		if(cur->microBehaviourInControl()) {
			continue;
		}
		if(!armyInTargetRegion) {
			BWTA::Chokepoint* cp = BWTA::getNearestChokepoint(effectiveTarget);
			//Broodwar->drawCircleMap(cp->getCenter().x(), cp->getCenter().y(), 96, Colors::Green, false);

			if(cur->isOnSmallChokePoint() && !cur->getUnit()->isMoving() && !cur->getUnit()->isAttacking() && !cur->getUnit()->isStartingAttack() && !cur->getUnit()->isAttackFrame() && cur->getUnit()->getOrder() != BWAPI::Orders::CastPsionicStorm) {
				//cur->getUnit()->move((currentWayPoint));
				// generate some points that are around the choke point, but in the region of the next waypoint
				// and at least n from the centre of the choke point
				ParticleGenerator* p = new ParticleGenerator(64, 200, cp->getCenter());
				std::vector<Position> v = p->generate();
				//BWTA::Region* curRegTar = BWTA::getRegion(currentWayPoint);
				for(std::vector<Position>::const_iterator it = v.begin(); it != v.end(); it++) {
					Position curPos = *it;
					if(BWTA::getRegion((TilePosition)curPos) == curRegTar) {

					} else {
						it = v.erase(it);
					}
					if(v.empty() || it == v.end()) {
						break;
					}
					if(curPos.getDistance(cp->getCenter()) < 64) {
						it = v.erase(it);
					}
					if(v.empty() || it == v.end()) {
						break;
					}
				} 

				if(!v.empty()) {
					random_shuffle(v.begin(), v.end());
					if(!armyInTargetRegion) {
						cur->getUnit()->move(v.at(0));
					}
					//Broodwar->drawEllipseMap(v.at(0).x(), v.at(0).y(), 16, 16, Colors::Green, true);
					//Broodwar->drawLineMap(cur->getPosition().x(), cur->getPosition().y(), v.at(0).x(), v.at(0).y(), Colors::Green);
				}
			}

		}

		//}
		//}
	}
	if(livingMembers == 0) {
		////OutputDebugString(TEXT("JUST CLERED MEMBERS"));
		return;
	}
	lastCentrePoint = centrePoint;
	centrePoint = Position(avgX/livingMembers, avgY/livingMembers);

	// now find the guy furthest away from this
	//	int furthestDistance = -1000;
	furthestDistance = 0;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		//int dist = cur->getPosition().getDistance(centrePoint);
		//if(dist > furthestDistance) {
		//	furthestDistance = dist;
		//}
		if(cur->getType().isFlyer()) {

		} else {
			if(cur->getUnit()->getType().size() == BWAPI::UnitSizeTypes::Small) {
				furthestDistance+=8;
			}
			if(cur->getUnit()->getType().size() == BWAPI::UnitSizeTypes::Medium) {
				furthestDistance+=10;
			}
			if(cur->getUnit()->getType().size() == BWAPI::UnitSizeTypes::Large) {
				furthestDistance+=12;
			}
		}
	}

	if(furthestDistance < 164) {
		furthestDistance = 164;
	}
	//Broodwar->drawEllipseMap(centrePoint.x(), centrePoint.y(), furthestDistance, furthestDistance, BWAPI::Colors::Blue, false);
	//Broodwar->drawTextMap(centrePoint.x(), centrePoint.y(), "%d", furthestDistance, BWAPI::Colors::White);


	//if(formed) {
	if(!movingToTargetRegion && !armyIsReforming) {
		//attackTargetRegion();
	} else {
		calculateArmyStructure();
	}
	//} 
	if(armyUnderAttack) {
		return;
	}
	if(armyInTargetRegion) {
		return;
	}
	int outOfPlaceCount = 0;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		if(cur->getUnit()->isLoaded() || cur->getType() == UnitTypes::Protoss_Shuttle || cur->getType() == UnitTypes::Protoss_Observer || unitIsInTargetRegion(cur)) {
			continue;
		}
		int dist = cur->getPosition().getDistance(centrePoint);
		if(dist <= furthestDistance) {

		} else {
			outOfPlaceCount++;
		}
	}
	//Broodwar->drawTextMap(centrePoint.x(), centrePoint.y()+16, "%d", outOfPlaceCount, BWAPI::Colors::White);
	if(reformFrameLimit > 0) {
		////////Broodwar->sendText("waiting for %d more frames", reformFrameLimit);
		reformFrameLimit--;
	} else {
		reformFrameLimit = -1;
	}
	if(outOfPlaceCount <= 4 && !path.empty() && !armyInTargetRegion) {
		armyIsReforming = false;
		movingToTargetRegion = true;
		formed = true;
		int MOVE_TICK = 8;
		if(Broodwar->getFrameCount()%MOVE_TICK == 0) {
			bool pauseDragoons = false;
			for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
			{
				UnitModel* cur = *i;
				if(!cur->isAlive() || cur->getUnit()->isStartingAttack() || cur->getUnit()->isAttacking() || cur->getUnit()->isAttackFrame() || cur->getUnit()->getOrder() == BWAPI::Orders::CastPsionicStorm) {
					continue;
				}
				// old solution
				if(cur->getUnit()->isLoaded()) {
					continue;
				}

				if(cur->getType() == UnitTypes::Protoss_Dragoon || cur->getType() == UnitTypes::Protoss_Zealot || cur->getType() == UnitTypes::Protoss_Archon || cur->getType() == UnitTypes::Protoss_Reaver) {
					if(reformFrameLimit > 0) {
						cur->getUnit()->stop(true);
						continue;
					} else {
						pauseDragoons = true;
					}
				}
				if(cur->getType() == UnitTypes::Protoss_Zealot ) {
					ZealotGeneralMicroBehaviour* z = (ZealotGeneralMicroBehaviour*)cur->getMicroBehaviour();
					if(z->getCurrentTarget() != NULL || (cur->getUnit()->isMoving() && cur->getUnit()->getTarget() != NULL) || cur->getUnit()->isAttacking() || cur->getUnit()->isStartingAttack()) {
						continue;
					}
				}
				if(cur->getType() == UnitTypes::Protoss_Dragoon) {
					if(cur->getMicroBehaviour() == NULL) {
						//////OutputDebugString(TEXT("WE HAVE A HUGE PORBLEM!!!"));
						continue;
					}
					ArcingDragoonMicroBehaviour* z = (ArcingDragoonMicroBehaviour*)cur->getMicroBehaviour();
					if(z->getCurrentTarget() != NULL || (cur->getUnit()->isMoving() && cur->getUnit()->getTarget() != NULL) || cur->getUnit()->isAttacking() || cur->getUnit()->isStartingAttack()) {
						continue;
					}
				}
				int FORMATION_DENSITY = 128;

				ParticleGenerator* p = new ParticleGenerator(16,FORMATION_DENSITY,currentWayPoint);
				std::vector<Position> v = p->generate();

				// maybe try to move to the best one of these?
				Position bestPos = Positions::None;
				for(std::vector<Position>::const_iterator it = v.begin(); it != v.end(); ++it) {
					Position ncur = *it;
					if(ncur.getDistance(effectiveTarget) > cur->getPosition().getDistance(effectiveTarget)) {
						it = v.erase(it);
						if(it == v.end() || v.empty()) {
							break;
						}
					}
				}
				if(v.empty()) {
					continue;
				}
				if(cur->getRegion() == curRegion) {
					cur->getUnit()->move(cur->findClosestPoint(v, Positions::None, -1));
				} else {
					cur->getUnit()->move(effectiveTarget);
				}
			}
			if(pauseDragoons) {
				reformFrameLimit = REFORM_WAIT_PERIOD+1;
			}
		}
		nextWayPoint();
	}

	/*
	for (std::vector<TilePosition>::iterator i = path.begin(); i != path.end(); ++i)
	{
		Position cur = (Position)(*i);
		Broodwar->drawBoxMap(cur.x(), cur.y(), cur.x()+16, cur.y()+16,BWAPI::Colors::Green, true);

	}
	
	//Broodwar->drawBoxMap(currentWayPoint.x(), currentWayPoint.y(), currentWayPoint.x()+20, currentWayPoint.y()+20,BWAPI::Colors::Red, true);

	for (std::vector<TilePosition>::iterator i = badPath.begin(); i != badPath.end(); ++i)
	{
		Position cur = (Position)(*i);
		////Broodwar->drawBoxMap(cur.x(), cur.y(), cur.x()+20, cur.y()+20,BWAPI::Colors::Cyan, true);
	}
*/
}

bool Army::isArmyUnderAttack()
{
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->isAlive()) {
			if(cur->isUnderThreat() || cur->getUnit()->isAttacking()) {
				lastAttacker = cur;
				return true;
			}
		}
	}
	return false;
}

void Army::rallyIdleMembers()
{
	if(Broodwar->getFrameCount()%24==0) {
		for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
		{
			UnitModel* cur = *i;
			if(cur->getType() == UnitTypes::Protoss_Archon || cur->getType() == UnitTypes::Protoss_Reaver || cur->getType() == UnitTypes::Protoss_Dragoon || cur->getType() == UnitTypes::Protoss_Zealot  || cur->getType() == UnitTypes::Protoss_Observer ||  cur->getType() == UnitTypes::Protoss_Shuttle) {


				if(cur->isAlive()) {
					if(!cur->getUnit()->isMoving() && cur->getUnit()->isIdle() && !cur->getUnit()->isAttacking() && !cur->getUnit()->isStartingAttack()) {
						if(overseer->getUnitManager()->getAllEnemyUnitsInRange(cur->getPosition(), cur->getType().sightRange()).empty()) {
							if(!cur->isFollowingPath()) {
								ParticleGenerator* g = new ParticleGenerator(members.size(), 64, lastAttacker->getPosition());
								TilePosition target = (TilePosition)g->generate().at(0);
								target = target.makeValid();
								if(cur->getUnit()->hasPath((Position)target)) {
									if((!Broodwar->getRegionAt((Position)target)->isHigherGround() && !Broodwar->getRegionAt(cur->getPosition())->isHigherGround()) || (Broodwar->getRegionAt((Position)target)->isHigherGround() && Broodwar->getRegionAt(cur->getPosition())->isHigherGround())) {
										//	cur->pathMove(target, PATHFINDING_THREATAWARE_ASTAR_GROUND_AVOIDUNITS);
										cur->getUnit()->move((Position)target);
										//cur->getUnit()->move(g->generate().at(0));
									}
								}
							}
						}
					}
				}
			}
		}
	}
}

void Army::addToArmyDirect( UnitModel* u )
{
	members.push_back(u);
}

bool Army::isAlive()
{
	return alive;
}

void Army::defendSelf()
{
	std::set<UnitModel*> beingAttacked;
	std::set<UnitModel*> notAttacking;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->isAlive()) {
			if(cur->getPosition().getDistance(centrePoint) < 768) {
				if(cur->getUnit()->isAttacking() || cur->getUnit()->isStartingAttack() || cur->getUnit()->isUnderAttack()) {
					beingAttacked.insert(cur);
				} else {
					if(cur->getType() != UnitTypes::Protoss_High_Templar && cur->getType() != UnitTypes::Protoss_Shuttle) {
						notAttacking.insert(cur);
					}
				}
			}
		}
	}

	// for now, lets just go to the first guy being attacked
	if(beingAttacked.empty() || notAttacking.empty()) {
		return;
	}
	UnitModel* prime = *(beingAttacked.begin());
	for (std::set<UnitModel*>::iterator i = notAttacking.begin(); i != notAttacking.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->getUnit()->isMoving()) {
			cur->getUnit()->move(prime->getPosition());
		}
	}
}

void Army::manageIdleMap()
{
	for(std::map<UnitModel*, int>::iterator i = idleMap.begin(); i != idleMap.end(); i++) {
		pair<UnitModel*, int> cur = *i;
		UnitModel* model = cur.first;
		int idleTime = cur.second;

		if(model->isStasised() || !model->isAlive()) {
			continue;
		}
		if(model->getType() == UnitTypes::Protoss_Shuttle || model->getType() == UnitTypes::Protoss_Observer) {
			continue;
		}
		if(((!model->getUnit()->isMoving() || (model->getUnit()->isMoving() && model->getPosition().getDistance(centrePoint) > furthestDistance))) && !model->getUnit()->isAttacking() && !model->getUnit()->isStartingAttack() && !model->getUnit()->isAttackFrame()) {
			//////Broodwar->sendText("before: %d", idleMap[model]);
			idleMap[model] += 1;
			//////Broodwar->sendText("after: %d", idleMap[model]);
		}
		if(idleTime >= 64) {
			//////Broodwar->sendText("moving along");
			model->getUnit()->move(currentWayPoint);
			idleMap[model] = 0;
		}
	}

}

void Army::assaultRegion()
{
	if(isContain) {
		return;
	}

	//std::vector<UnitModel*> regionUnits = overseer->getUnitManager()->getAllEnemyBuildingsInRegion(target);
	BaseModel* closestBase = overseer->getUnitManager()->getEnemyBaseModelInRegion(target);
	// firstly, if we don't see anything in the region, spread our units out over the region and find stuff to attack
	// actually, maybe this is all we need to do?
	if(tickCount == 0) {
		// need to find a new target here
		////Broodwar->sendText("locating new target");
		/*
		BWTA::Region* r = overseer->getUnitManager()->getBelievedEnemyMainBaseRegionNot(target);
		if(r == NULL) {
		return;
		}
		*/
		if(isSupportSquad()) {
			disband();
		} else {
		BWTA::Region* newTar = findNewTarget();
		if(newTar != NULL) {
			////OutputDebugString(TEXT("NEW TARGET NOT NULL\n"));
			initialize();
			setTarget(newTar);
			formUp();
			calculatePath();
			transformPath();
			
		} else {
			////OutputDebugString(TEXT("NEW TARGET NULL\n"));
		}
		}
		tickCount = 128;
		return;
	}
	// attack something from the region
	if((closestBase != NULL && closestBase->isAlive()) || (isSupportSquad() && !overseer->getUnitManager()->getAllEnemyBuildingsInRegion(curRegion).empty())) {

		if(Broodwar->getFrameCount()%128 == 0) {

			////Broodwar->sendText("exploring!!");
			Position rootPos = target->getCenter();
			int nmax = 512;
			if(closestBase != NULL) {
			UnitModel* bcur = closestBase->getRandomBuilding();
			if(bcur != NULL) {
				rootPos = bcur->getPosition();
				nmax = 196;
			}
			}
			ParticleGenerator* p = new ParticleGenerator(128, nmax, rootPos);
			std::vector<Position> v = p->generate();

			for(std::vector<Position>::iterator k = v.begin(); k != v.end(); k++) {
				Position cur = *k;
				if(BWTA::getRegion(cur) == target) {

				} else {
					k = v.erase(k);
					if(k == v.end()) {
						break;
					}
				}
			}
			if(v.empty()) {
				return;
			}

			for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
			{
				UnitModel* j = *i;

				if(j->getUnit()->isMoving() || !j->isAlive() || j->isBeingTargetted() || j->getUnit()->isAttackFrame() || j->getUnit()->isAttacking() || j->getUnit()->isStartingAttack() || j->isUnderThreat()) {
					continue;
				}

				for(std::vector<Position>::iterator k = v.begin(); k != v.end(); k++) {
					Position cur = *k;

					j->getUnit()->attack(cur);
					k = v.erase(k);
					if(k == v.end()) {
						break;
					}

				}
			}

		}	

	} else {
		if(tickCount > 0){
			tickCount--;
		}
	}
}

BWAPI::Position Army::getCentrePoint()
{
	return centrePoint;
}

void Army::manageAirReplacementRequests()
{
	// for now, just deal with arbiters and observers
	int numArbiters = 0;
	int numObservers = 0;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->isAlive()) {
			if(cur->getType() == UnitTypes::Protoss_Arbiter) {
				numArbiters++;
			}
			if(cur->getType() == UnitTypes::Protoss_Observer) {		
				numObservers++;
			}
		}
	}

	if(numArbiters < 1) {
		std::vector<UnitModel*> units = overseer->getUnitManager()->getAllFriendlyUnitsOfType(UnitTypes::Protoss_Arbiter);
		for (std::vector<UnitModel*>::iterator it = units.begin(); it != units.end(); ++it)
		{
			UnitModel* cur = *it;
			if(cur->getArmyOwner() == NULL) {
				addToArmy(cur);
				cur->getUnit()->move(centrePoint);
				return;
			}
		}
	}
	if(numObservers < 1) {
		std::vector<UnitModel*> units = overseer->getUnitManager()->getAllFriendlyUnitsOfType(UnitTypes::Protoss_Observer);
		for (std::vector<UnitModel*>::iterator it = units.begin(); it != units.end(); ++it)
		{
			UnitModel* cur = *it;
			if(cur->getArmyOwner() == NULL) {
				addToArmy(cur);
				cur->getUnit()->move(centrePoint);
				return;
			}
		}
	}

}

UnitModel* Army::getLastAttacker()
{
	return lastAttacker;
}

void Army::removeFromArmy( UnitType t )
{
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->getType() == t) {
			if(cur->isAlive()) {
				cur->clearMicroBehaviour();
				cur->getUnit()->move(overseer->getUnitManager()->getFriendlyMainBase()->getPosition());
				i = members.erase(i);
			}
		}
	}
}

void Army::removeFromArmy( UnitModel* u )
{
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); i++)
	{
		UnitModel* cur = *i;
		if(cur == u) {
			i = members.erase(i);
			break;
		}
	}
}

bool Army::positionIsInTargetRegion( Position p )
{
	return BWTA::getRegion(p) == target;
}

bool Army::unitIsInTargetRegion( UnitModel* p )
{
	return p->getRegion() == curRegion;
}

void Army::clearChokePointObstructions()
{
	if(Broodwar->getFrameCount()%128 == 0) {
		if(initialForceSize >= 12) {
			if(BWTA::getNearestChokepoint(centrePoint)->getCenter().getDistance(centrePoint) <= 196) {
				std::vector<UnitModel*> units = overseer->getUnitManager()->getAllFriendlyUnitsInRange(BWTA::getNearestChokepoint(centrePoint)->getCenter(), 128);
				for (std::vector<UnitModel*>::iterator i = units.begin(); i != units.end(); ++i)
				{
					UnitModel* cur = *i;
					if(!cur->isOwnedByPlayer() || cur->getType().isBuilding()) {
						continue;
					}
					if(cur->getArmyOwner() == this) {
						continue;
					}
					if(!cur->getUnit()->isMoving()) {
						cur->getUnit()->move(overseer->getUnitManager()->getClosestFriendlyBaseModel(cur->getPosition())->getSubject()->getPosition());
					}
				}
			}
		}
	}
}

void Army::manageGroundReplacementRequests()
{
	BaseModel* nearestBase = overseer->getUnitManager()->getClosestFriendlyBaseModel(centrePoint);
	if(curRegion != nearestBase->getBaseRegion() || centrePoint.getDistance(nearestBase->getPosition()) > 768) {
		return;
	}
	std::vector<UnitModel*> potentialReinforcements = nearestBase->getDefenders();
	for (std::vector<UnitModel*>::iterator i = potentialReinforcements.begin(); i != potentialReinforcements.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		if(cur->getArmyOwner() != NULL) {
			continue;
		}
		int numTypePresent = countNumTypeInArmy(cur->getType());
		int numTypeDesired = initialStateMap[cur->getType()];
		if(numTypePresent < numTypeDesired) {
			////Broodwar->sendText("picking up a reinforcement!!");
			addToArmy(cur);
			cur->getUnit()->move(centrePoint);
		}

	}



}

int Army::countNumTypeInArmy( UnitType t )
{
	int c = 0;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		if(cur->getType() == t) {
			c++;
		}
	}
	return c;


}

bool Army::checkAlive()
{

	if(members.empty() || members.size() == 0 || !alive) {
		return false;
	}
	int numAlive = 0;
	for (std::vector<UnitModel*>::iterator i = members.begin(); i != members.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->isAlive() && cur->getType() != UnitTypes::Protoss_Observer && cur->getType() != UnitTypes::Protoss_Arbiter && cur->getType() != UnitTypes::Protoss_Shuttle) {
			numAlive++;
		}

	}
	int deathThresh = (int)(initialForceSize*DEATH_THRESHOLD);
	if(deathThresh < 4) {
		deathThresh = 4;
	}
	if(numAlive >= deathThresh) {
		return true;
	}

	if(numAlive < 4) {
		disband();
		return false;
	}
	return true;
}

bool Army::isSupportSquad()
{
	return supportSquad;
}


void Army::setSupportSquad()
{
	supportSquad = true;
}

int Army::getInitialForceSize()
{
	return initialForceSize;
}

BWTA::Region* Army::findNewTarget()
{
	BWTA::Region* bestTarget = overseer->getUnitManager()->getBelievedEnemyMainBaseRegion();

	// if we actually have something to pick from
	if(bestTarget != NULL) {

		int bval = 500000000;
		if(!isSupportSquad()) {
			bval = 0;
		}
		std::set<BWTA::Region*> regions = BWTA::getRegions();
		BWTA::Region* bestBase = NULL;
		for (std::set<BWTA::Region*>::iterator i = regions.begin(); i != regions.end(); ++i)
		{
			BWTA::Region* cur = *i;
			if(overseer->getUnitManager()->isBlackListed(cur)) {
				continue;
			}
			bool underAssault = overseer->getOffenseMonitor()->isRegionUnderAttack((*i));
			if(underAssault) {
				continue;
			}
			int cval = overseer->getUnitManager()->valueRegion(cur);
			if(cval == 0) {
				continue;
			}

			if(!isSupportSquad()) {
				if(cval > bval) {
					bval = cval;
					bestBase = cur;
				}
			} else {
				if(cval < bval) {
					bval = cval;
					bestBase = cur;
				}
			}
		}

		if(bestBase != NULL) {
			return bestBase;
		} else {
			// if, after all that, we can't find anything... just attack what ever you want
			return bestTarget;
		}
	} else {
		// if we have no idea where the enemy base is, lets just find some random uncontrolled base location to go explore
		std::set<BWTA::Region*> regions = BWTA::getRegions();
		for (std::set<BWTA::Region*>::iterator i = regions.begin(); i != regions.end(); ++i)
		{
			BWTA::Region* cur = *i;
			if(cur == curRegion) {
				continue;
			}
			if(cur->getBaseLocations().empty()) {
				continue;
			}
			if(overseer->getUnitManager()->isBlackListed(cur)) {
				continue;
			}
			bool underAssault = overseer->getOffenseMonitor()->isRegionUnderAttack((*i));
			bool moreThanOneBase = false;
			if((overseer->getUnitManager()->getEnemyBaseModels().size() > 1)) {
				moreThanOneBase = true;
			}
			if(underAssault && moreThanOneBase) {
				continue;
			}
			if(overseer->getUnitManager()->isRegionOwnedByMe(cur)) {
				continue;
			}

			if(!Broodwar->isExplored((TilePosition)cur->getCenter())) {
				return cur;
			}

			InformationCell* c = overseer->getUnitManager()->getMapInformationSystem()->getBaseCellAt(cur);
			if(c != NULL) {
				if(c->getInformationValue() >= 3000) {
					return cur;
				}
			}

		}




	}
	return NULL;
}

void Army::disband()
{
	for (std::vector<UnitModel*>::iterator it = members.begin(); it != members.end(); ++it)
	{
		UnitModel* cur = *it;
		cur->clearArmyOwner();
		cur->setCurrentTaskType(NO_TASK);

		if(cur->isAlive()) {
			if(cur->getUnit()->isAttacking() || cur->getUnit()->isStartingAttack() || cur->getUnit()->isAttackFrame()) {
			} else {
				if(cur->getType() == UnitTypes::Protoss_Observer) {
					cur->setMicroBehaviour(PROTOSS_SCOUTING_OBSERVER);
					continue;
				} 
				if(cur->getType() == UnitTypes::Protoss_Shuttle) {
					cur->clearMicroBehaviour();
				}
					cur->getUnit()->move(overseer->getUnitManager()->getClosestFriendlyBaseModel(cur->getPosition())->getPosition());
				
			}

			}
		}
	

	members.clear();
	idleMap.clear();
}

bool Army::isContainingForce()
{
	return isContain;
}

BWTA::Region* Army::getCurrentTarget()
{
	return target;
}

