Menu

[r815]: / Trunk / Sources / CvUnitAI.cpp  Maximize  Restore  History

Download this file

33564 lines (29226 with data), 1.0 MB

// unitAI.cpp

#include "CvGameCoreDLL.h"
#include "CvUnitAI.h"
#include "CvMap.h"
#include "CvArea.h"
#include "CvPlot.h"
#include "CvGlobals.h"
#include "CvGameAI.h"
#include "CvTeamAI.h"
#include "CvPlayerAI.h"
#include "CvGameCoreUtils.h"
#include "CvRandom.h"
#include "CyUnit.h"
#include "CyArgsList.h"
#include "CvDLLPythonIFaceBase.h"
#include "CvInfos.h"
#include "FProfiler.h"
#include "FAStarNode.h"
#include "CvReachablePlotSet.h"

// interface uses
#include "CvDLLInterfaceIFaceBase.h"
#include "CvDLLFAStarIFaceBase.h"

#include <boost/bind.hpp>

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/02/09                                jdog5000      */
/*                                                                                              */
/* AI logging                                                                                   */
/************************************************************************************************/
#include "BetterBTSAI.h"
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
PlayerTypes	CvUnitAI::m_cachedPlayer = NO_PLAYER;
CvReachablePlotSet*	CvUnitAI::m_cachedMissionaryPlotset = NULL;
static PlayerTypes eCachedTargetCityPlayer = NO_PLAYER;
static PlayerTypes eCachedAttackOddsPlayer = NO_PLAYER;

static bool plotOpaqueInfoMatches(int iOpaqueInfo, int activityId, int iValue)
{
	bool	bResult = false;

	switch(activityId)
	{
	case ACTIVITY_ID_ANY_ATTACK:
		bResult = (iOpaqueInfo != 0 && iValue > (iOpaqueInfo-1)/100);
		break;
	case ACTIVITY_ID_EXPLORE:
		bResult = (iValue == iOpaqueInfo);
		break;
	case ACTIVITY_ID_PILLAGE:
		bResult = (iValue == iOpaqueInfo);
		break;
	}

	return bResult;
}

void	CvUnitAI::AI_clearCaches(void)
{
	m_cachedPlayer = NO_PLAYER;
	SAFE_DELETE(m_cachedMissionaryPlotset);

	eCachedTargetCityPlayer = NO_PLAYER;
	eCachedAttackOddsPlayer = NO_PLAYER;
}

#define	MAX_SEARCH_RANGE			25
#define	MAX_BARB_TARGET_CITY_RANGE	20

#define FOUND_RANGE					(7)

typedef struct
{
	CvPlot*	plot;
	int		value;
} plotValue;

static bool plotValueSortPredicate(const plotValue& d1, const plotValue& d2)
{
	//	Sort largest first
	return d1.value < d2.value;
}

// Public Functions...

CvUnitAI::CvUnitAI(bool bIsDummy) : CvUnit(bIsDummy)
{
	AI_reset(NO_UNITAI, true);
}


CvUnitAI::~CvUnitAI()
{
	AI_uninit();
}


void CvUnitAI::AI_init(UnitAITypes eUnitAI, int iBirthmark)
{
	AI_reset(eUnitAI);

	//--------------------------------
	// Init other game data
	AI_setBirthmark(iBirthmark);

	FAssertMsg(AI_getUnitAIType() != NO_UNITAI, "AI_getUnitAIType() is not expected to be equal with NO_UNITAI");
	GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), 1);
}


void CvUnitAI::AI_uninit()
{
}


void CvUnitAI::AI_reset(UnitAITypes eUnitAI, bool bConstructorCall)
{
	FAssert(bConstructorCall || eUnitAI != NO_UNITAI);

	AI_uninit();

	m_iBirthmark = 0;

	m_eUnitAIType = eUnitAI;
	
	m_iAutomatedAbortTurn = -1;

	m_iGroupLeadOverride = -1;

	m_contractsLastEstablishedTurn = -1;
	m_contractualState = CONTRACTUAL_STATE_NONE;

	m_eIntendedConstructBuilding = NO_BUILDING;
	
	m_iPredictedHitPoints = -1;
	m_bHasAttacked = false;

	m_iGarrisonCity = -1;
	m_iGenericValue = -1;
}

// AI_update returns true when we should abort the loop and wait until next slice
bool CvUnitAI::AI_update()
{
	PROFILE_FUNC();
	MEMORY_TRACK();

	CvUnit* pTransportUnit;
	
	OutputDebugString(CvString::format("AI_Update for unit %d of owner %d\n", m_iID, m_eOwner).c_str());

#ifdef _DEBUG
	getGroup()->validateLocations();
#endif

	//	If canMove() is false there is not much we can do.  Empirically this can happen
	//	Not sure why but suspect either:
	//	1) The loop in CvPlayer that calls AI_Update() for the active player but only ends turn
	//	   when there are no non-busy or moveable units left.  Each time around this loop it's
	//	   possible for units to be left in this state due to unexecutable orders, and stack splits
	//	   which causes ALL units to be asked to reconsider their orders again the next time round the loop
	//	2) When not all units in the stack have the same movement allowance and the head unit can't move after
	//	   execution of the current order
	//	Whatever the cause, the safest thing to do is just push a SKIP without the expense of considering all
	//	the other possibilities it won't be able to execute anyway due to having no movement left
	if ( !canMove() )
	{
		if ( !getGroup()->isBusy() )
		{
			getGroup()->pushMission(MISSION_SKIP);
		}
		return false;
	}

	getGroup()->setActivityType(ACTIVITY_AWAKE);

	FAssertMsg(isGroupHead(), "isGroupHead is expected to be true"); // XXX is this a good idea???
/************************************************************************************************/
/* Afforess	                  Start		 02/20/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	if(GC.getUSE_AI_UPDATE_UNIT_CALLBACK())
	{
		PYTHON_ACCESS_LOCK_SCOPE

		// allow python to handle it
		CyUnit* pyUnit = new CyUnit(this);
		CyArgsList argsList;
		argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class
		long lResult=0;
		PYTHON_CALL_FUNCTION4(__FUNCTION__, PYGameModule, "AI_unitUpdate", argsList.makeFunctionArgs(), &lResult);
		delete pyUnit;	// python fxn must not hold on to this pointer
		if (lResult == 1)
		{
			return false;
		}
	}

	CvReachablePlotSet::ClearCache();

/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	if (getDomainType() == DOMAIN_LAND)
	{
/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 07/07/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		if (plot()->isWater() && !canMoveAllTerrain() && !plot()->isCanMoveLandUnits())
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
		{
			getGroup()->pushMission(MISSION_SKIP);
			return false;
		}
		else
		{
			pTransportUnit = getTransportUnit();

			if (pTransportUnit != NULL)
			{
				if (pTransportUnit->getGroup()->hasMoved() || (pTransportUnit->getGroup()->headMissionQueueNode() != NULL))
				{
					getGroup()->pushMission(MISSION_SKIP);
					return false;
				}
			}
		}
	}

	if (AI_afterAttack())
	{
		return false;
	}
	if (getGroup()->isAutomated())
	{
		switch (getGroup()->getAutomateType())
		{
		case AUTOMATE_BUILD:
			if (AI_getUnitAIType() == UNITAI_WORKER)
			{
				AI_workerMove();
			}
			else if (AI_getUnitAIType() == UNITAI_WORKER_SEA)
			{
				AI_workerSeaMove();
			}
			else
			{
				FAssert(false);
			}
			break;

		case AUTOMATE_NETWORK:
			AI_networkAutomated();
			// XXX else wake up???
			break;

		case AUTOMATE_CITY:
			AI_cityAutomated();
			// XXX else wake up???
			break;

		case AUTOMATE_EXPLORE:
			switch (getDomainType())
			{
			case DOMAIN_SEA:
				AI_exploreSeaMove();
				break;

			case DOMAIN_AIR:
				// if we are cargo (on a carrier), hold if the carrier is not done moving yet
				pTransportUnit = getTransportUnit();
				if (pTransportUnit != NULL)
				{
					if (pTransportUnit->isAutomated() && pTransportUnit->canMove() && pTransportUnit->getGroup()->getActivityType() != ACTIVITY_HOLD)
					{
						getGroup()->pushMission(MISSION_SKIP);
						break;
					}
				}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/12/09                                jdog5000      */
/*                                                                                              */
/* Player Interface                                                                             */
/************************************************************************************************/
				// Have air units explore like AI units do
				AI_exploreAirMove();
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		
				break;

			case DOMAIN_LAND:
				AI_exploreMove();
				break;

			default:
				FAssert(false);
				break;
			}
			
			// if we have air cargo (we are a carrier), and we done moving, explore with the aircraft as well
			if (hasCargo() && domainCargo() == DOMAIN_AIR && (!canMove() || getGroup()->getActivityType() == ACTIVITY_HOLD))
			{
				std::vector<CvUnit*> aCargoUnits;
				getCargoUnits(aCargoUnits);
				for (uint i = 0; i < aCargoUnits.size() && isAutomated(); ++i)
				{
					CvUnit* pCargoUnit = aCargoUnits[i];
					if (pCargoUnit->getDomainType() == DOMAIN_AIR)
					{
						if (pCargoUnit->canMove())
						{
							pCargoUnit->getGroup()->setAutomateType(AUTOMATE_EXPLORE);
							pCargoUnit->getGroup()->setActivityType(ACTIVITY_AWAKE);
						}
					}
				}
			}
			break;

		case AUTOMATE_RELIGION:
			if (AI_getUnitAIType() == UNITAI_MISSIONARY)
			{
				AI_missionaryMove();
			}
			break;
/************************************************************************************************/
/* Afforess	                  Start		 09/16/10                                               */
/*                                                                                              */
/* Advanced Automations                                                                         */
/************************************************************************************************/
		case AUTOMATE_PILLAGE:
			AI_AutomatedpillageMove();
			break;
		case AUTOMATE_HUNT:
			AI_SearchAndDestroyMove();
			break;
		case AUTOMATE_CITY_DEFENSE:
			AI_cityDefense();
			break;
		case AUTOMATE_NATIONAL_DEFENSE:
			AI_nationalDefense();
			break;
		case AUTOMATE_BORDER_PATROL:
			AI_borderPatrol();
			break;
		case AUTOMATE_PIRATE:
			AI_pirateSeaMove();
			break;
		case AUTOMATE_HURRY:
			AI_merchantMove();
			break;
		//Yes, these automations do the same thing, but they act differently for different units. 
		case AUTOMATE_AIRSTRIKE:
		case AUTOMATE_AIRBOMB:
			AI_autoAirStrike();
			break;
		case AUTOMATE_AIR_RECON:
			AI_exploreAirMove();
			break;
		case AUTOMATE_UPGRADING:
		case AUTOMATE_CANCEL_UPGRADING:
		case AUTOMATE_PROMOTIONS:
		case AUTOMATE_CANCEL_PROMOTIONS:
			FAssertMsg(false, "SelectionGroup Should Not be Using These Automations!")
			break;
		case AUTOMATE_SHADOW:
			//	If we've lost the unit qwe should be shadowing (not sure how this can happen but empirically
			//	it's been seen) then lose the automation
			if( getShadowUnit() == NULL )
			{
				getGroup()->setAutomateType(NO_AUTOMATE);
			}
			else
			{
				AI_shadowMove();
			}
			break;
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
		default:
			FAssert(false);
			break;
		}
	
		// if no longer automated, then we want to bail
		return (!isDelayedDeath() && !getGroup()->isAutomated());
	}
	else
	{
		//	No confirmed garrison city until we reaffirm it with another set
		m_iAffirmedGarrisonCity = -1;

		if ( isBarbarian() )
		{
			PROFILE("CvUnitAI::AI_Update.barbarian");

			doUnitAIMove();
		}
		else
		{
			PROFILE("CvUnitAI::AI_Update.civ");

			doUnitAIMove();
		}

		if ( m_iGarrisonCity != -1 && m_iAffirmedGarrisonCity == -1 )
		{
			//	This group has done something else (presumably of higher priority)
			//	so should no longer be considered part of the city's garrison
			AI_setAsGarrison(NULL);
		}
	}

#ifdef _DEBUG
	if ( NULL != getGroup() && !isDelayedDeath() )
	{
		getGroup()->validateLocations();
	}
#endif

	return (!isDelayedDeath() && AI_isAwaitingContract());
}

void CvUnitAI::doUnitAIMove(void)
{
	//	If a unit has a contract mission for a unit that has just finished
	//	give the unit a chance to hook up with it by force-processing contracts
	//	before doing other AI activities
	if ( getGroup()->AI_getMissionAIType() == MISSIONAI_CONTRACT_UNIT &&
		 processContracts() )
	{
		return;
	}

	switch (AI_getUnitAIType())
	{
	case UNITAI_UNKNOWN:
		getGroup()->pushMission(MISSION_SKIP);
		break;

	case UNITAI_ANIMAL:
		AI_animalMove();
		break;

	case UNITAI_SETTLE:
		AI_settleMove();
		break;

	case UNITAI_WORKER:
		AI_workerMove();
		break;

	case UNITAI_ATTACK:
		if (isBarbarian())
		{
			AI_barbAttackMove();
		}
		else
		{
			AI_attackMove();
		}
		break;

	case UNITAI_ATTACK_CITY:
		AI_attackCityMove();
		break;

	case UNITAI_COLLATERAL:
		AI_collateralMove();
		break;

	case UNITAI_PILLAGE:
		AI_pillageMove();
		break;

	case UNITAI_RESERVE:
		AI_reserveMove();
		break;

	case UNITAI_COUNTER:
		AI_counterMove();
		break;

	case UNITAI_PILLAGE_COUNTER:
		AI_pillageCounterMove();
		break;

	case UNITAI_PARADROP:
		AI_paratrooperMove();
		break;

	case UNITAI_CITY_DEFENSE:
		AI_cityDefenseMove();
		break;

	case UNITAI_CITY_COUNTER:
	case UNITAI_CITY_SPECIAL:
		AI_cityDefenseExtraMove();
		break;

	case UNITAI_EXPLORE:
		AI_exploreMove();
		break;

	case UNITAI_HUNTER:
		AI_SearchAndDestroyMove();
		break;

	case UNITAI_MISSIONARY:
		AI_missionaryMove();
		break;

	case UNITAI_PROPHET:
		AI_prophetMove();
		break;

	case UNITAI_ARTIST:
		AI_artistMove();
		break;

	case UNITAI_SCIENTIST:
		AI_scientistMove();
		break;

	case UNITAI_GENERAL:
		AI_generalMove();
		break;

	case UNITAI_MERCHANT:
		AI_merchantMove();
		break;

	case UNITAI_SUBDUED_ANIMAL:
		AI_subduedAnimalMove();
		break;

	case UNITAI_ENGINEER:
		AI_engineerMove();
		break;

	case UNITAI_SPY:
		AI_spyMove();
		break;

	case UNITAI_ICBM:
		AI_ICBMMove();
		break;

	case UNITAI_WORKER_SEA:
		AI_workerSeaMove();
		break;

	case UNITAI_ATTACK_SEA:
		if (isBarbarian())
		{
			AI_barbAttackSeaMove();
		}
		else
		{
			AI_attackSeaMove();
		}
		break;

	case UNITAI_RESERVE_SEA:
		AI_reserveSeaMove();
		break;

	case UNITAI_ESCORT_SEA:
		AI_escortSeaMove();
		break;

	case UNITAI_EXPLORE_SEA:
		AI_exploreSeaMove();
		break;

	case UNITAI_ASSAULT_SEA:
		AI_assaultSeaMove();
		break;

	case UNITAI_SETTLER_SEA:
		AI_settlerSeaMove();
		break;

	case UNITAI_MISSIONARY_SEA:
		AI_missionarySeaMove();
		break;

	case UNITAI_SPY_SEA:
		AI_spySeaMove();
		break;

	case UNITAI_CARRIER_SEA:
		AI_carrierSeaMove();
		break;

	case UNITAI_MISSILE_CARRIER_SEA:
		AI_missileCarrierSeaMove();
		break;

	case UNITAI_PIRATE_SEA:
		AI_pirateSeaMove();
		break;

	case UNITAI_ATTACK_AIR:
		AI_attackAirMove();
		break;

	case UNITAI_DEFENSE_AIR:
		AI_defenseAirMove();
		break;

	case UNITAI_CARRIER_AIR:
		AI_carrierAirMove();
		break;

	case UNITAI_MISSILE_AIR:
		AI_missileAirMove();
		break;

	case UNITAI_ATTACK_CITY_LEMMING:
		AI_attackCityLemmingMove();
		break;
		
/************************************************************************************************/
/* Great Diplomat MOD               START                                                  		*/
/************************************************************************************************/
	case UNITAI_DIPLOMAT:
		AI_diplomat();
		break;
/************************************************************************************************/
/* Great Diplomat MOD               END                                                  		*/
/************************************************************************************************/

	default:
		FAssert(false);
		break;
	}
}

//	Note death (or capture) of a unit
void CvUnitAI::AI_killed(void)
{
	if ( UNITAI_WORKER == AI_getUnitAIType() )
	{
		CvPlot* pMissionPlot = getGroup()->AI_getMissionAIPlot();

		if (pMissionPlot != NULL && pMissionPlot->getWorkingCity() != NULL)
		{
			if (getGroup()->AI_getMissionAIType() == MISSIONAI_BUILD && getArea() == pMissionPlot->getArea())
			{
				OutputDebugString(CvString::format("Worker at (%d,%d) killed with mission for city %S\n", plot()->getX_INLINE(), plot()->getY_INLINE(), pMissionPlot->getWorkingCity()->getName().GetCString()).c_str());
				pMissionPlot->getWorkingCity()->AI_changeWorkersHave(-1);
			}
		}
	}

	if( gUnitLogLevel >= 2 )
	{
		//	Logging of death location and some mission info
		CvPlot* pMissionPlot = getGroup()->AI_getMissionAIPlot();

		logBBAI("%S's %S (%d) died at (%d,%d), mission was %d",GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), m_iID,plot()->getX_INLINE(),plot()->getY_INLINE(),getGroup()->getMissionType(0));
		if (pMissionPlot != NULL )
		{
			logBBAI("    Mission plot was (%d,%d)", pMissionPlot->getX_INLINE(), pMissionPlot->getY_INLINE());
		}
	}

	//	Increment the general danger count for this plot's vicinity
	if ( getGroup()->AI_getMissionAIType() != MISSIONAI_DELIBERATE_KILL )
	{
		GET_PLAYER(getOwnerINLINE()).addPlotDangerSource(plot(), GC.getGameINLINE().AI_combatValue(getUnitType()) + 100);

	//	Killing units may change danger evaluation so clear the plot danger cache
#ifdef PLOT_DANGER_CACHING
		CvPlayerAI::ClearPlotDangerCache();
#endif
	}
}

// Returns true if took an action or should wait to move later...
bool CvUnitAI::AI_follow()
{
	if (AI_followBombard())
	{
		return true;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/31/10                              jdog5000        */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
	// Pushing MISSION_MOVE_TO missions when not all units could move resulted in stack being
	// broken up on the next turn.  Also, if we can't attack now we don't want to queue up an
	// attack for next turn, better to re-evaluate.
	bool bCanAllMove = getGroup()->canAllMove();

	if( bCanAllMove )
	{
		if (AI_cityAttack(1, 65, true))
		{
			return true;
		}
	}

	if (isEnemy(plot()->getTeam()))
	{
		if (getGroup()->canPillage(plot()))
		{
			getGroup()->pushMission(MISSION_PILLAGE);
			return true;
		}
	}

	if( bCanAllMove )
	{
		if (AI_anyAttack(1, 70, 2, true, true))
		{
			return true;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (isFound())
	{
		if (area()->getBestFoundValue(getOwnerINLINE()) > 0)
		{
			if (AI_foundRange(FOUND_RANGE, true))
			{
				return true;
			}
		}
	}

	return false;
}


// XXX what if a unit gets stuck b/c of it's UnitAIType???
// XXX is this function costing us a lot? (it's recursive...)
void CvUnitAI::AI_upgrade()
{
	PROFILE_FUNC();

//	FAssertMsg(!isHuman(), "isHuman did not return false as expected");
	FAssertMsg(AI_getUnitAIType() != NO_UNITAI, "AI_getUnitAIType() is not expected to be equal with NO_UNITAI");

	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
	UnitAITypes eUnitAI = AI_getUnitAIType();
	CvArea* pArea = area();
/************************************************************************************************/
/* RevDCM	                  Start		 05/11/09                                               */
/*                                                                                              */
/* Upgrade Correction                                                                           */
/************************************************************************************************/
	CvCivilizationInfo& kCivilization = GC.getCivilizationInfo(kPlayer.getCivilizationType());
	UnitTypes eLoopUnit;
	UnitTypes eBestUnit;

	int iCurrentValue = kPlayer.AI_unitValue(getUnitType(), eUnitAI, pArea);

	std::vector<int> aPotentialUnitClassTypes = GC.getUnitInfo(getUnitType()).getUpgradeUnitClassTypes();

	for (int iPass = 0; iPass < 2; iPass++)
	{
		eBestUnit = NO_UNIT;
		int iBestValue = 0;

		for (int iI = 0; iI < (int)aPotentialUnitClassTypes.size(); iI++)
		{
			eLoopUnit = (UnitTypes)kCivilization.getCivilizationUnits((UnitClassTypes)aPotentialUnitClassTypes[iI]);
			if (eLoopUnit != NO_UNIT && ((iPass > 0) || GC.getUnitInfo(eLoopUnit).getUnitAIType(eUnitAI)))
			{
				int iNewValue = kPlayer.AI_unitValue(eLoopUnit, (iPass == 0 ? eUnitAI : (UnitAITypes)GC.getUnitInfo(eLoopUnit).getDefaultUnitAIType()), pArea);
				if ((iPass == 0 || iNewValue > 0) && iNewValue > iCurrentValue)
				{
					if (canUpgrade(eLoopUnit))
					{
						int iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Upgrade"));

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							eBestUnit = eLoopUnit;
/************************************************************************************************/
/* RevDCM	                     END                                                            */
/************************************************************************************************/
						}
					}
				}
			}
		}

		if (eBestUnit != NO_UNIT)
		{
			if( gUnitLogLevel >= 2 )
			{
				logBBAI("    %S at (%d,%d) upgrading to %S", getName(0).GetCString(), plot()->getX_INLINE(), plot()->getY_INLINE(), GC.getUnitInfo(eBestUnit).getDescription());
			}
			upgrade(eBestUnit);
			doDelayedDeath();
			return;
		}
	}
}


void CvUnitAI::AI_promote()
{
	PROFILE_FUNC();

	PromotionTypes eBestPromotion;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	eBestPromotion = NO_PROMOTION;

	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
		if (canPromote((PromotionTypes)iI, -1))
		{
			iValue = AI_promotionValue((PromotionTypes)iI);

			if (iValue > iBestValue)
			{
				iBestValue = iValue;
				eBestPromotion = ((PromotionTypes)iI);
			}
		}
	}

	if (eBestPromotion != NO_PROMOTION)
	{
		if( gUnitLogLevel > 2 )
		{
			CvWString szString;
			getUnitAIString(szString, AI_getUnitAIType());
			logBBAI("    %S's %S chooses promotion %S", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), GC.getPromotionInfo(eBestPromotion).getDescription());
		}

		promote(eBestPromotion, -1);
		AI_promote();
	}
}

int CvUnitAI::AI_groupFirstVal()
{
	if ( m_iGroupLeadOverride != -1 )
	{
		return m_iGroupLeadOverride;
	}

	switch (AI_getUnitAIType())
	{
	case UNITAI_UNKNOWN:
	case UNITAI_ANIMAL:
		return LEADER_PRIORITY_MIN;
		break;

	case UNITAI_SETTLE:
		return 21;
		break;

	case UNITAI_WORKER:
		return 20;
		break;

	//	Koshling - changed priorities of UNITAI_ATTACK and UNITAI_ATTACK_CITY
	//	to be constants with city attack higher.  Previiosuly they overlapped, and were
	//	dependent on collateral damage and bombardment.  This is (a) no longer necessary
	//	since the AI routines now check the group capability (so the unit with the capability
	//	doesn't have to be the leader for it to be used); and (b) overlapping lead to
	//	bad behaviiur where an ATTACK unit would join a city attack stack and become the lead,
	//	then realise there was a problem next turn and split the group, then rejoin the
	//	following turn, ...
	case UNITAI_ATTACK:
		return 14;

	case UNITAI_ATTACK_CITY:
		return 17;

	case UNITAI_COLLATERAL:
		return 7;
		break;

	case UNITAI_PILLAGE:
		return 12;
		break;

	case UNITAI_RESERVE:
		return 6;
		break;

	case UNITAI_COUNTER:
		return 5;
		break;

	case UNITAI_CITY_DEFENSE:
		return 3;
		break;

	case UNITAI_CITY_COUNTER:
	case UNITAI_PILLAGE_COUNTER:
		return 2;
		break;

	case UNITAI_CITY_SPECIAL:
		return 1;
		break;

	case UNITAI_PARADROP:
		return 4;
		break;

	case UNITAI_SUBDUED_ANIMAL:
		return 7;	//	Must be less than the result for UNITAI_HUNTER
		break;

	case UNITAI_EXPLORE:
	case UNITAI_HUNTER:
		return 8;
		break;

	case UNITAI_MISSIONARY:
		return 10;
		break;

	case UNITAI_PROPHET:
	case UNITAI_ARTIST:
	case UNITAI_SCIENTIST:
	case UNITAI_GENERAL:
	case UNITAI_MERCHANT:
	case UNITAI_ENGINEER:
		return 11;
		break;

	case UNITAI_SPY:
		return 9;
		break;

	case UNITAI_ICBM:
		break;

	case UNITAI_WORKER_SEA:
		return 8;
		break;

	case UNITAI_ATTACK_SEA:
		return 3;
		break;

	case UNITAI_RESERVE_SEA:
		return 2;
		break;

	case UNITAI_ESCORT_SEA:
		return 1;
		break;

	case UNITAI_EXPLORE_SEA:
		return 5;
		break;

	case UNITAI_ASSAULT_SEA:
		return 11;
		break;

	case UNITAI_SETTLER_SEA:
		return 9;
		break;

	case UNITAI_MISSIONARY_SEA:
		return 9;
		break;

	case UNITAI_SPY_SEA:
		return 10;
		break;

	case UNITAI_CARRIER_SEA:
		return 7;
		break;

	case UNITAI_MISSILE_CARRIER_SEA:
		return 6;
		break;

	case UNITAI_PIRATE_SEA:
		return 4;
		break;

	case UNITAI_ATTACK_AIR:
	case UNITAI_DEFENSE_AIR:
	case UNITAI_CARRIER_AIR:
	case UNITAI_MISSILE_AIR:
		break;

	case UNITAI_ATTACK_CITY_LEMMING:
		return 1;
		break;

/************************************************************************************************/
/* Great Diplomat MOD               START                                                  		*/
/************************************************************************************************/
	case UNITAI_DIPLOMAT:
		return 15;
		break;
/************************************************************************************************/
/* Great Diplomat MOD               END                                                  		*/
/************************************************************************************************/

	default:
		FAssert(false);
		break;
	}

	return 0;
}


int CvUnitAI::AI_groupSecondVal()
{
	return ((getDomainType() == DOMAIN_AIR) ? airBaseCombatStr() : baseCombatStr());
}

int CvUnitAI::AI_getPredictedHitPoints(void) const
{
	return m_iPredictedHitPoints;
}

void CvUnitAI::AI_setPredictedHitPoints(int iPredictedHitPoints)
{
	m_iPredictedHitPoints	= iPredictedHitPoints;
	if ( iPredictedHitPoints == -1 )
	{
		//	This is a reset
		m_bHasAttacked			= false;
	}
}

bool CvUnitAI::AI_getHasAttacked()
{
	return m_bHasAttacked;
}

// Returns attack odds out of 100 (the higher, the better...)
// Withdrawal odds included in returned value
int CvUnitAI::AI_attackOdds(const CvPlot* pPlot, bool bPotentialEnemy, CvUnit** ppDefender)
{
	PROFILE_FUNC();

	CvUnit* pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, !bPotentialEnemy, bPotentialEnemy);
	if ( ppDefender != NULL )
	{
		*ppDefender = pDefender;
	}

	return AI_attackOddsAtPlot(pPlot, pDefender, (ppDefender != NULL));
}

// Returns attack odds out of 100 (the higher, the better...)
// Withdrawal odds included in returned value
int CvUnitAI::AI_attackOddsAtPlot(const CvPlot* pPlot, CvUnit* pDefender, bool modifyPredictedResults)
{
	PROFILE_FUNC();

	if (pDefender == NULL)
	{
		return 100;
	}

	static stdext::hash_map<int,int>* resultsCache = NULL;

	CvChecksum cacheKey;

	if ( modifyPredictedResults )
	{
		m_bHasAttacked = true;
	}
	else
	{
		if ( eCachedAttackOddsPlayer != getOwnerINLINE() || resultsCache == NULL )
		{
			if ( resultsCache == NULL )
			{
				resultsCache = new stdext::hash_map<int,int>();
			}
			else
			{
				resultsCache->clear();
			}

			eCachedAttackOddsPlayer = getOwnerINLINE();
		}

		cacheKey.add(pPlot->getX_INLINE());
		cacheKey.add(1024*pPlot->getY_INLINE());
		cacheKey.add(getID());
		cacheKey.add(pDefender->getID());

		stdext::hash_map<int,int>::const_iterator itr = resultsCache->find(cacheKey.get());
		if ( itr != resultsCache->end() )
		{
			return itr->second;
		}
	}

	int iResult = AI_attackOddsAtPlotInternal(pPlot, pDefender, modifyPredictedResults);

	if ( !modifyPredictedResults )
	{
		(*resultsCache)[cacheKey.get()] = iResult;
	}

	return iResult;
}

int CvUnitAI::AI_attackOddsAtPlotInternal(const CvPlot* pPlot, CvUnit* pDefender, bool modifyPredictedResults)
{
	PROFILE_FUNC();
#if 0
	int iOurStrength;
	int iTheirStrength;
	int iOurFirepower;
	int iTheirFirepower;
	int iBaseOdds;
	int iStrengthFactor;
	int iDamageToUs;
	int iDamageToThem;
	int iNeededRoundsUs;
	int iNeededRoundsThem;
	int iHitLimitThem;
#endif
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/21/10                                jdog5000      */
/*                                                                                              */
/* Efficiency, Lead From Behind                                                                 */
/************************************************************************************************/

	//Afforess: use combat odds for AI calculations, no good reason for custom odds logic.
	int iOdds = (getCombatOdds(this, pDefender) + 5) / 10;
	//	Koshling - modify the calculated odds to account for withdrawal chances
	//	and the AI player's rose-tinted-spectacles value - this used to simply add
	//	to the odds, but that made it look like fights with hugely different strengths
	//	still had 5%ish chances of voctory which was a good expected gain so caused the 
	//	AI to suicide weak units onto strong enemy ones, thinking that one in 20 or so would
	//	win againts a massively stronger opponent.  Changed it to be multiplicative instead
	iOdds += (iOdds * GET_PLAYER(getOwnerINLINE()).AI_getAttackOddsChange() + (100 - iOdds) * withdrawalProbability()) / 100;

	return std::max(1, std::min(iOdds, 99));

#if 0

	iOurStrength = ((getDomainType() == DOMAIN_AIR) ? airCurrCombatStr(NULL) : pDefender->currCombatStr(NULL, NULL));
	iOurFirepower = ((getDomainType() == DOMAIN_AIR) ? iOurStrength : pDefender->currFirepower(NULL, NULL));

	if (iOurStrength == 0)
	{
		return 1;
	}

	int iTheirOdds;


	getDefenderCombatValues(*pDefender, pPlot, iOurStrength, iOurFirepower, iTheirOdds, iTheirStrength, iDamageToUs, iDamageToThem, NULL, pDefender);
	iBaseOdds = 100 - iTheirOdds/10;	//	getDefenderCombatValues returns odds based on the combat die (which is 1000 sided)

	iTheirStrength = pDefender->currCombatStr(pPlot, this);
	iTheirFirepower = pDefender->currFirepower(pPlot, this);


	FAssert((iOurStrength + iTheirStrength) > 0);
	FAssert((iOurFirepower + iTheirFirepower) > 0);

	iBaseOdds = (100 * iOurStrength) / (iOurStrength + iTheirStrength);

	if (iBaseOdds == 0)
	{
		return 1;
	}

	iStrengthFactor = ((iOurFirepower + iTheirFirepower + 1) / 2);

	// UncutDragon
/* original code
	iDamageToUs = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iTheirFirepower + iStrengthFactor)) / (iOurFirepower + iStrengthFactor)));
	iDamageToThem = std::max(1,((GC.getDefineINT("COMBAT_DAMAGE") * (iOurFirepower + iStrengthFactor)) / (iTheirFirepower + iStrengthFactor)));
*/	// modified
	iDamageToUs = std::max(1,((GC.getCOMBAT_DAMAGE() * (iTheirFirepower + iStrengthFactor)) / (iOurFirepower + iStrengthFactor)));
	iDamageToThem = std::max(1,((GC.getCOMBAT_DAMAGE() * (iOurFirepower + iStrengthFactor)) / (iTheirFirepower + iStrengthFactor)));
	// /UncutDragon
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	iHitLimitThem = pDefender->maxHitPoints() - combatLimit();

	iNeededRoundsUs = (std::max(0, pDefender->currHitPoints() - iHitLimitThem) + iDamageToThem - 1 ) / iDamageToThem;
	iNeededRoundsThem = (std::max(0, currHitPoints()) + iDamageToUs - 1 ) / iDamageToUs;

	if (getDomainType() != DOMAIN_AIR)
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/30/09                      Mongoose & jdog5000     */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
		// From Mongoose SDK
		if (!pDefender->immuneToFirstStrikes()) {
			iNeededRoundsUs   -= ((iBaseOdds * firstStrikes()) + ((iBaseOdds * chanceFirstStrikes()) / 2)) / 100;
		}
		if (!immuneToFirstStrikes()) {
			iNeededRoundsThem -= (((100 - iBaseOdds) * pDefender->firstStrikes()) + (((100 - iBaseOdds) * pDefender->chanceFirstStrikes()) / 2)) / 100;
		}
		iNeededRoundsUs   = std::max(1, iNeededRoundsUs);
		iNeededRoundsThem = std::max(1, iNeededRoundsThem);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	}

	int iRoundsDiff = iNeededRoundsUs - iNeededRoundsThem;
	if (iRoundsDiff > 0)
	{
		if ( modifyPredictedResults )
		{
			AI_setPredictedHitPoints(0);

			FAssert(pDefender->currHitPoints() > iNeededRoundsThem*iDamageToThem);
			pDefender->AI_setPredictedHitPoints(pDefender->currHitPoints() - iNeededRoundsThem*iDamageToThem);
		}

		iTheirStrength *= (1 + iRoundsDiff);
	}
	else
	{
		if ( modifyPredictedResults )
		{
			pDefender->AI_setPredictedHitPoints(0);

			//	If iRoundsDiff == 0 both units can wind up at a notional 0 HP so cannot assert left over
			//	HP in that case
			AI_setPredictedHitPoints(std::max(0,currHitPoints() - iNeededRoundsUs*iDamageToUs));
		}

		iOurStrength *= (1 - iRoundsDiff);
	}

	int iOdds = (((iOurStrength * 100) / (iOurStrength + iTheirStrength)));

	//	Koshling - modify the calculated odds to account for withdrawal chances
	//	and the AI player's rose-tinted-spectacles value - this used to simply add
	//	to the odds, but that made it look like fights with hugely different strengths
	//	still had 5%ish chances of voctory which was a good expected gain so caused the 
	//	AI to suicide weak units onto strong enemy ones, thinking that one in 20 or so would
	//	win againts a massively stronger opponent.  Changed it to be multiplicative instead
	iOdds += (iOdds*2*GET_PLAYER(getOwnerINLINE()).AI_getAttackOddsChange() + (100 - iOdds) * withdrawalProbability()) / 100;

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/30/09                      Mongoose & jdog5000     */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	// From Mongoose SDK
	return range(iOdds, 1, 99);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
#endif

}


// Returns true if the unit found a build for this city...
bool CvUnitAI::AI_bestCityBuild(CvCity* pCity, CvPlot** ppBestPlot, BuildTypes* peBestBuild, CvPlot* pIgnorePlot, CvUnit* pUnit)
{
	PROFILE_FUNC();

	BuildTypes eBuild;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	BuildTypes eBestBuild = NO_BUILD;
	CvPlot* pBestPlot = NULL;

	
	for (int iPass = 0; iPass < 2; iPass++)
	{
/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 06/17/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		for (iI = 0; iI < pCity->getNumCityPlots(); iI++)
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
		{
			CvPlot* pLoopPlot = plotCity(pCity->getX_INLINE(), pCity->getY_INLINE(), iI);

			//if (pLoopPlot != NULL)
			if (pLoopPlot != NULL && pLoopPlot->getWorkingCity() == pCity) // K-Mod (karadoc)
			{
				if (AI_plotValid(pLoopPlot))
				{
					if (pLoopPlot != pIgnorePlot)
					{
/************************************************************************************************/
/* Afforess	                  Start		 01/19/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
						if ((pLoopPlot->getImprovementType() == NO_IMPROVEMENT) || !(GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION) && !(pLoopPlot->getImprovementType() == (GC.getDefineINT("RUINS_IMPROVEMENT"))) && !(GC.getImprovementInfo((ImprovementTypes)pLoopPlot->getImprovementType()).isDepletedMine())))
						{
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
							iValue = pCity->AI_getBestBuildValue(iI);

							if (iValue > iBestValue)
							{
								eBuild = pCity->AI_getBestBuild(iI);
								FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");

								if (eBuild != NO_BUILD)
								{
									if (0 == iPass)
									{
										iBestValue = iValue;
										pBestPlot = pLoopPlot;
										eBestBuild = eBuild;
									}
									else if (canBuild(pLoopPlot, eBuild))
									{
										if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this)))
										{
											int iPathTurns;
											if (generatePath(pLoopPlot, 0, true, &iPathTurns))
											{
												// XXX take advantage of range (warning... this could lead to some units doing nothing...)
												int iMaxWorkers = 1;
												if (getPathMovementRemaining() == 0)
												{
													iPathTurns++;
												}
												else if (iPathTurns <= 1)
												{
													iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, eBuild);										
												}
												if (pUnit != NULL)
												{
													if (pUnit->plot()->isCity() && iPathTurns == 1 && getPathMovementRemaining() > 0)
													{
														iMaxWorkers += 10;
													}
												}	
												if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
												{
													//XXX this could be improved greatly by
													//looking at the real build time and other factors
													//when deciding whether to stack.
													iValue /= (iPathTurns+1);

													iBestValue = iValue;
													pBestPlot = pLoopPlot;
													eBestBuild = eBuild;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
		
		if (0 == iPass)
		{
			if (eBestBuild != NO_BUILD)
			{
				FAssert(pBestPlot != NULL);
				int iPathTurns;
				if ((!pBestPlot->isVisible(getTeam(),false) || !pBestPlot->isVisibleEnemyUnit(this)) &&
					canBuild(pBestPlot, eBestBuild) &&
					generatePath(pBestPlot, 0, true, &iPathTurns) )
				{
					int iMaxWorkers = 1;
					if (pUnit != NULL)
					{
						if (pUnit->plot()->isCity())
						{
							iMaxWorkers += 10;
						}
					}	
					if (getPathMovementRemaining() == 0)
					{
						iPathTurns++;
					}
					else if (iPathTurns <= 1)
					{
						iMaxWorkers = AI_calculatePlotWorkersNeeded(pBestPlot, eBestBuild);										
					}
					int iWorkerCount = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pBestPlot, MISSIONAI_BUILD, getGroup());
					if (iWorkerCount < iMaxWorkers)
					{
						//Good to go.
						break;
					}
				}
				eBestBuild = NO_BUILD;
				iBestValue = 0;
			}			
		}
	}
	
	if (NO_BUILD != eBestBuild)
	{
		FAssert(NULL != pBestPlot);
		if (ppBestPlot != NULL)
		{
			*ppBestPlot = pBestPlot;
		}
		if (peBestBuild != NULL)
		{
			*peBestBuild = eBestBuild;
		}
	}


	return (NO_BUILD != eBestBuild);
}


bool CvUnitAI::AI_isCityAIType() const
{
	return ((AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
		      (AI_getUnitAIType() == UNITAI_CITY_COUNTER) ||
					(AI_getUnitAIType() == UNITAI_CITY_SPECIAL) ||
						(AI_getUnitAIType() == UNITAI_RESERVE) ||
							(AI_getUnitAIType() == UNITAI_PILLAGE_COUNTER) ||
								//Afforess: count units on guard mission as city defenders
								(getGroup()->AI_getMissionAIType() == MISSIONAI_GUARD_CITY));
}


int CvUnitAI::AI_getBirthmark() const
{
	return m_iBirthmark;
}


void CvUnitAI::AI_setBirthmark(int iNewValue)
{
	m_iBirthmark = iNewValue;
	if (AI_getUnitAIType() == UNITAI_EXPLORE_SEA)
	{
		if (GC.getGame().circumnavigationAvailable())
		{
			m_iBirthmark -= m_iBirthmark % 4;
			int iExplorerCount = GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(UNITAI_EXPLORE_SEA);
			iExplorerCount += getOwnerINLINE() % 4;
			if (GC.getMap().isWrapX())
			{
				if ((iExplorerCount % 2) == 1)
				{
					m_iBirthmark += 1;
				}
			}
			if (GC.getMap().isWrapY())
			{
				if (!GC.getMap().isWrapX())
				{
					iExplorerCount *= 2;
				}
					
				if (((iExplorerCount >> 1) % 2) == 1)
				{
					m_iBirthmark += 2;
				}
			}
		}
	}
}


UnitAITypes CvUnitAI::AI_getUnitAIType() const
{
	//	A unit should never have no unitAI so if that state
	//	is found to exist (empirically it's been seen but the underlying cause
	//	has not yet been found) set it to its default AI
	if ( m_eUnitAIType == NO_UNITAI )
	{
		FAssertMsg(false,"Unit has no UnitAI!");

		((CvUnitAI*)this)->m_eUnitAIType = (UnitAITypes)m_pUnitInfo->getDefaultUnitAIType();

		area()->changeNumAIUnits(getOwnerINLINE(), m_eUnitAIType, 1);
		GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(m_eUnitAIType, 1);
	}

	return m_eUnitAIType;
}


// XXX make sure this gets called...
void CvUnitAI::AI_setUnitAIType(UnitAITypes eNewValue)
{
	FAssertMsg(eNewValue != NO_UNITAI, "NewValue is not assigned a valid value");

	if (AI_getUnitAIType() != eNewValue)
	{
		area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), -1);
		GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), -1);

		m_eUnitAIType = eNewValue;

		area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), 1);
		GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), 1);

		joinGroup(NULL);
	}
}

int CvUnitAI::AI_sacrificeValue(const CvPlot* pPlot) const
{
    int iValue;
    int iCollateralDamageValue = 0;
    if (pPlot != NULL)
    {
        int iPossibleTargets = std::min((pPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits());

        if (iPossibleTargets > 0)
        {
            iCollateralDamageValue = collateralDamage();
            iCollateralDamageValue += std::max(0, iCollateralDamageValue - 100);
            iCollateralDamageValue *= iPossibleTargets;
            iCollateralDamageValue /= 5;
        }
    }

	if (getDomainType() == DOMAIN_AIR) 
	{
		iValue = 128 * (100 + currInterceptionProbability());
		if (m_pUnitInfo->getNukeRange() != -1)
		{
			iValue += 25000;
		}
		iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
		iValue *= (maxHitPoints() - getDamage());
		iValue /= 100;
	} 
	else 
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      05/14/10                                jdog5000      */
/*                                                                                              */
/* General AI                                                                                   */
/************************************************************************************************/
/* 
// original bts code
		iValue  = 128 * (currEffectiveStr(pPlot, ((pPlot == NULL) ? NULL : this)));
		iValue *= (100 + iCollateralDamageValue);
		iValue /= (100 + cityDefenseModifier());
		iValue *= (100 + withdrawalProbability());	
		iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
		iValue /= (10 + getExperience());
*/
		iValue  = 128 * (currEffectiveStr(pPlot, ((pPlot == NULL) ? NULL : this)));

		if ( iValue > 0 )
		{
			iValue *= (100 + iCollateralDamageValue);
			iValue /= (100 + cityDefenseModifier());
			iValue *= (100 + withdrawalProbability());

			// Experience and medics now better handled in LFB
			iValue /= (10 + getExperience());
			if( !GC.getLFBEnable() )
			{
				iValue *= 10;
				iValue /= (10 + getSameTileHeal() + getAdjacentTileHeal());
			}

			// Value units which can't kill units later, also combat limits mean higher survival odds
			if (combatLimit() < 100)
			{
				iValue *= 150;
				iValue /= 100;

				iValue *= 100;
				iValue /= std::max(1, combatLimit());
			}

			iValue /= std::max(1, (1 + m_pUnitInfo->getProductionCost()));
		}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      05/14/10                                jdog5000      */
/*                                                                                              */
/* From Lead From Behind                                                                        */
/************************************************************************************************/
	// From Lead From Behind by UncutDragon
	if (GC.getLFBEnable() && iValue > 0)
	{
		// Reduce the value of sacrificing 'valuable' units - based on great general, limited, healer, experience
		iValue *= 100;
		int iRating = LFBgetRelativeValueRating();
		if (iRating > 0)
		{
			iValue /= (1 + 3*iRating);
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

    return iValue;
}

// Protected Functions...

void CvUnitAI::AI_animalMove()
{
	PROFILE_FUNC();

	//TB Animal Mod Begin
#ifdef C2C_BUILD
	if (!isBarbarian())
	{
		FAssertMsg(false, "Subdued animal still has animal AI");
		OutputDebugString("Choosing animal mission\n");
		if (AI_heal())
		{
			OutputDebugString("Chosen to heal\n");
			return;
		}

		if (AI_construct())
		{
			OutputDebugString("Chosen to construct\n");
			return;
		}

		if (AI_guardCity())
		{
			OutputDebugString("Chosen to guard city\n");
			return;
		}

		OutputDebugString("No valid choice - skipping\n");
	}
	else
#endif
	{
		if (GC.getGameINLINE().getSorenRandNum(100, "Animal Attack") < GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAnimalAttackProb())
		{
			if (AI_anyAttack(1, 0))
			{
				return;
			}
		}

		if (AI_heal())
		{
			return;
		}

		if (AI_patrol())
		{
			return;
		}
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_settleMove()
{
	PROFILE_FUNC();

	if (GET_PLAYER(getOwnerINLINE()).getNumCities() == 0)
	{
/************************************************************************************************/
/* Afforess & Fuyu	                  Start      09/18/10                                       */
/*                                                                                              */
/* Check for Good City Sites Near Starting Location                                             */
/************************************************************************************************/
		int iGameSpeedPercent = ( (2 * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent())
			+ GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent()
			+ GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getResearchPercent() ) / 4;
		int iMaxFoundTurn = (iGameSpeedPercent + 50) / 150; //quick 0, normal/epic 1, marathon 2
		if ( canMove() && !GET_PLAYER(getOwnerINLINE()).AI_isPlotCitySite(plot()) && GC.getGameINLINE().getElapsedGameTurns() <= iMaxFoundTurn )
		{
			int iBestValue = 0;
			int iBestFoundTurn = 0;
			CvPlot* pBestPlot = NULL;

			for (int iCitySite = 0; iCitySite < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iCitySite++)
			{
				CvPlot* pCitySite = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iCitySite);
				if (pCitySite->getArea() == getArea() || canMoveAllTerrain())
				{
					//int iPlotValue = GET_PLAYER(getOwnerINLINE()).AI_foundValue(pCitySite->getX_INLINE(), pCitySite->getY_INLINE());
					int iPlotValue = pCitySite->getFoundValue(getOwnerINLINE());
					if (iPlotValue > iBestValue)
					{
						int iPathTurns;
						//Can this unit reach the plot this turn? (getPathLastNode()->m_iData2 == 1)
						//Will this unit still have movement points left to found the city the same turn? (getPathLastNode()->m_iData1 > 0))
						if (generatePath(pCitySite,0,false,&iPathTurns))
						{
							int iFoundTurn = GC.getGameINLINE().getElapsedGameTurns() + iPathTurns - ((getPathMovementRemaining() > 0)? 1 : 0);
							if (iFoundTurn <= iMaxFoundTurn)
							{
								iPlotValue *= 100; //more precision
								//the slower the game speed, the less penality the plotvalue gets for long walks towards it. On normal it's -18% per turn
								iPlotValue *= 100 - std::min( 100, ( (1800/iGameSpeedPercent) * iFoundTurn ) );
								iPlotValue /= 100;
								if (iPlotValue > iBestValue)
								{
									iBestValue = iPlotValue;
									iBestFoundTurn = iFoundTurn;
									pBestPlot = pCitySite;
								}
							}
						}
					}
				}
			}

			if (pBestPlot != NULL)
			{
				//Don't give up coast or river, don't settle on bonus with food
				if ( (plot()->isRiver() && !pBestPlot->isRiver())
					|| (plot()->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) && !pBestPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
					|| (pBestPlot->getBonusType(NO_TEAM) != NO_BONUS && pBestPlot->calculateNatureYield(YIELD_FOOD, getTeam(), true) > 0) )
				{
					pBestPlot = NULL;
				}
			}

			if (pBestPlot != NULL)
			{
				if( gUnitLogLevel >= 2 )
				{
					logBBAI("    Settler not founding in place but moving %d, %d to nearby city site at %d, %d (%d turns away) with value %d)", (pBestPlot->getX_INLINE() - plot()->getX_INLINE()), (pBestPlot->getY_INLINE() - plot()->getY_INLINE()), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), iBestFoundTurn, iBestValue);
				}
				getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pBestPlot);
				return;
			}
		}
/************************************************************************************************/
/* Afforess & Fuyu	                     END                                                    */
/************************************************************************************************/



		// RevDCM TODO: What makes sense for rebels here?
		if (canFound(plot()))
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/02/09                                jdog5000      */
/*                                                                                              */
/* AI logging                                                                                   */
/************************************************************************************************/
			if( gUnitLogLevel >= 2 )
			{
				logBBAI("    Settler founding in place due to no cities");
			}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

			getGroup()->pushMission(MISSION_FOUND);
			return;
		}
	}
	
	int iDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3);
	
	if (iDanger > 0)
	{
		if ((!getGroup()->canDefend() && ((plot()->getOwnerINLINE() == getOwnerINLINE()) || (iDanger > 2))) ||
			GET_PLAYER(getOwnerINLINE()).AI_getVisiblePlotDanger(plot(), 2, false, getGroup(), 70))
		{
			if (AI_retreatToCity())
			{
				return;
			}
			if (AI_safety())
			{
				return;
			}
			getGroup()->pushMission(MISSION_SKIP);
		}
	}

	//	Don't found new cities if that would cause more unhappiness when we already have
	//	happiness issues
	bool bInhibitFounding = false;

	if (GET_PLAYER(getOwnerINLINE()).getCityLimit() > 0)
	{
		if ( GET_PLAYER(getOwnerINLINE()).getCityOverLimitUnhappy() > 0 )
		{
			//	Soft limit.  If we already have unhappy cities don't create
			//	settlers that will increase overall unhappiness as they found
			//	new cities
			bInhibitFounding = (GET_PLAYER(getOwnerINLINE()).getCityLimit() <= GET_PLAYER(getOwnerINLINE()).getNumCities() &&
								GET_PLAYER(getOwnerINLINE()).AI_getOverallHappyness(GET_PLAYER(getOwnerINLINE()).getCityOverLimitUnhappy()) < 0);
		}
		else
		{
			//	Hard limit
			bInhibitFounding = (GET_PLAYER(getOwnerINLINE()).getCityLimit() <= GET_PLAYER(getOwnerINLINE()).getNumCities());
		}
	}

	if ( !bInhibitFounding )
	{
		bInhibitFounding = GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble();

		if( bInhibitFounding && gUnitLogLevel >= 2 )
		{
			logBBAI("    Settler inhibitted from founding due to financial difficulties");
		}
	}
	else
	{
		if( gUnitLogLevel >= 2 )
		{
			logBBAI("    Settler inhibitted from founding due to city limit unhappyness");
		}
	}

	if ( !bInhibitFounding )
	{
		int iAreaBestFoundValue = 0;
		int iOtherBestFoundValue = 0;

		for (int iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
		{
			CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
	/************************************************************************************************/
	/* UNOFFICIAL_PATCH                       01/10/09                                jdog5000      */
	/*                                                                                              */
	/* Bugfix, settler AI                                                                           */
	/************************************************************************************************/
	/* original bts code
			if (pCitySitePlot->getArea() == getArea())
	*/
			// Only count city sites we can get to
			if ((pCitySitePlot->getArea() == getArea() || canMoveAllTerrain()) && generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true))
	/************************************************************************************************/
	/* UNOFFICIAL_PATCH                        END                                                  */
	/************************************************************************************************/
			{
				if (plot() == pCitySitePlot)
				{
					if (canFound(plot()))
					{
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      10/02/09                                jdog5000      */
	/*                                                                                              */
	/* AI logging                                                                                   */
	/************************************************************************************************/
						if( gUnitLogLevel >= 2 )
						{
							logBBAI("    Settler founding in place since it's at a city site %d, %d", getX_INLINE(), getY_INLINE());
						}
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/

						getGroup()->pushMission(MISSION_FOUND);
						return;					
					}
				}
				// K-Mod. If we are already heading to this site, then keep going!
				// This change fixes a bug which prevented settlers from targetting the same site two turns in a row!
				else
				{
					CvPlot* pMissionPlot = getGroup()->AI_getMissionAIPlot();
					if (pMissionPlot == pCitySitePlot && getGroup()->AI_getMissionAIType() == MISSIONAI_FOUND)
					{
						// safety check. (cf. conditions in AI_found)
						if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pMissionPlot, MISSIONAI_GUARD_CITY) > 0)
						{
							if( gUnitLogLevel >= 2 )
							{
								logBBAI("    Settler continuing mission to %d, %d", pCitySitePlot->getX_INLINE(), pCitySitePlot->getY_INLINE());
							}
							CvPlot* pEndTurnPlot = getPathEndTurnPlot();
							getGroup()->pushMission(MISSION_MOVE_TO, pEndTurnPlot->getX(), pEndTurnPlot->getY(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pCitySitePlot);
							return;
						}
					}
				}
				// K-Mod end
				iAreaBestFoundValue = std::max(iAreaBestFoundValue, pCitySitePlot->getFoundValue(getOwnerINLINE()));

			}
			else if ( canDefend() )	//	Might have failed due to danger when we are unstacked which doesn't imply another area/need for transports
			{
				iOtherBestFoundValue = std::max(iOtherBestFoundValue, pCitySitePlot->getFoundValue(getOwnerINLINE()));
			}
		}

	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      01/16/09                                jdog5000      */
	/*                                                                                              */
	/* Gold AI                                                                                      */
	/************************************************************************************************/
		// No new settling of colonies when AI is in financial trouble
		if( plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
		{
			if( GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble() )
			{
				// Thomas SG
				//iOtherBestFoundValue = 0;
				iOtherBestFoundValue /= 4;
			}
		}
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/

		
		if ((iAreaBestFoundValue == 0) && (iOtherBestFoundValue == 0))
		{
			if ((GC.getGame().getGameTurn() - getGameTurnCreated()) > 20)
			{
				if (NULL != getTransportUnit())
				{
					getTransportUnit()->unloadAll();
				}

				if (NULL == getTransportUnit())
				{
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      11/30/08                                jdog5000      */
	/*                                                                                              */
	/* Unit AI                                                                                      */
	/************************************************************************************************/
	/* original bts code
					//may seem wasteful, but settlers confuse the AI.
					scrap();
					return;
	*/
					if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(getGroup()->getHeadUnit(), MISSIONAI_PICKUP) == 0 )
					{
						//may seem wasteful, but settlers confuse the AI.
						scrap();
						return;
					}
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/
				}
			}
		}
		
		if ((iOtherBestFoundValue * 100) > (iAreaBestFoundValue * 110))
		{
			if (plot()->getOwnerINLINE() == getOwnerINLINE())
			{
				if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
				{
					return;
				}
			}
		}
		
		if ((iAreaBestFoundValue > 0) && plot()->isBestAdjacentFound(getOwnerINLINE()))
		{
			if (canFound(plot()))
			{
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      10/02/09                                jdog5000      */
	/*                                                                                              */
	/* AI logging                                                                                   */
	/************************************************************************************************/
				if( gUnitLogLevel >= 2 )
				{
					logBBAI("    Settler founding in place due to best adjacent found");
				}
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/
				getGroup()->pushMission(MISSION_FOUND);
				return;
			}
		}

		if (!GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_PEACE) &&
			!GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) &&
			(!getGroup()->canDefend() || getGroup()->getStrength() < 2*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE)))
		{
			//	If we're already in a city advertise for an escort
			if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()) && !isCargo())
			{
				if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )
				{
					//	For now advertise the work as being here since we'll be holding position
					//	while we wait for a defender.  It would be more optimal to 'meet' the defender
					//	on the way or at the target plot, but this might leave us exposed on the way so
					//	the calculations involved are somewhat harder and not attempted for now
					if( gUnitLogLevel >= 3 )
					{
						logBBAI("    Settler for player %d (%S) at (%d,%d) requesting defensive escort\n",
								getOwner(),
								GET_PLAYER(getOwner()).getCivilizationDescription(0),
								plot()->getX_INLINE(),
								plot()->getY_INLINE());
					}

					GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(HIGH_PRIORITY_ESCORT_PRIORITY, DEFENSIVE_UNITCAPABILITIES, plot()->getX_INLINE(), plot()->getY_INLINE(), this, UNITAI_CITY_DEFENSE, 2*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE));

					m_contractsLastEstablishedTurn = GC.getGameINLINE().getGameTurn();
					m_contractualState = CONTRACTUAL_STATE_AWAITING_ANSWER;

					return;
				}
#if 0
				else
				{
					//	No units were available to escort us.  Let the city know that building some might
					//	be a good idea
					plot()->getPlotCity()->AI_noteUnitEscortNeeded();
				}
#endif
			}

			// Afforess: removed, uneeded, causes settlers to get stuck in cities.
//			if (AI_retreatToCity())
//			{
//				return;
//			}
		}

		if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
		{
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
	/*                                                                                              */
	/* Unit AI, Efficiency                                                                          */
	/************************************************************************************************/
			//if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0) 
			if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot())) 
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/
				&& (GC.getGameINLINE().getMaxCityElimination() > 0))
			{
				if (getGroup()->getNumUnits() < 3)
				{
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}
			}
		}

		if (iAreaBestFoundValue > 0)
		{
			if (AI_found())
			{
				return;
			}
		}

		if (plot()->getOwnerINLINE() == getOwnerINLINE())
		{
			if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
			{
				return;
			}

			// BBAI TODO: Go to a good city (like one with a transport) ...
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_workerMove()
{
	PROFILE_FUNC();
	
	CvCity* pCity;
	bool bCanRoute;
	bool bNextCity;

	bCanRoute = canBuildRoute();
	bNextCity = false;

	// XXX could be trouble...
	if (!getGroup()->canDefend() && plot()->getOwnerINLINE() != getOwnerINLINE())
	{
		//	Try to get an immediate escort
		if ( !isHuman() && AI_workerNeedsToAwaitDefender(plot(), 1, false) )
		{
			return;
		}

		//	Look for a local group we can join to be safe!
		AI_setLeaderPriority(LEADER_PRIORITY_MIN);	//	We don't want to take control

		if ( AI_group(UNITAI_HUNTER, -1, -1, -1, false, true, false, 1) )
		{
			return;
		}
		if ( AI_group(UNITAI_ATTACK, -1, -1, -1, true, true, false, 1) )
		{
			return;
		}
		if ( AI_group(UNITAI_ATTACK_CITY, -1, -1, -1, true, true, false, 1) )
		{
			return;
		}
		if ( AI_group(UNITAI_COUNTER, -1, -1, -1, true, true, false, 1) )
		{
			return;
		}

		AI_setLeaderPriority(-1);	//	We didn't get to group so back to normal

		//	Nobody can join us and we cannot join anyone else - run for it!
		if (AI_retreatToCity())
		{
			return;
		}
	}
	//ls612: Combat Worker Danger Evaluation
	bool bWorkerDanger = ((plot()->getOwnerINLINE() != getOwnerINLINE() && GET_PLAYER(getOwnerINLINE()).AI_isPlotThreatened(plot(), 2)) || ((plot()->getOwnerINLINE() == getOwnerINLINE()) && (exposedToDanger(plot(), 80, false))));

	if (canDefend() && getGroup()->getNumUnits() == 1 && bWorkerDanger)
	{
		// in this order, retreat to safety, or go into a city
		if (AI_safety())
		{
			return;
		}
		if (AI_retreatToCity())
		{
			return;
		}
	}

	if (!isHuman())
	{
		if ( AI_workerReleaseDefenderIfNotNeeded() )
		{
			return;
		}

		if (plot()->getOwnerINLINE() == getOwnerINLINE())
		{
			if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 2, -1, -1, 0, MOVE_SAFE_TERRITORY))
			{
				return;
			}
		}
	}

	if (AI_construct(MAX_INT, MAX_INT, 15, true))
	{
		OutputDebugString(CvString::format("%S (%d) chooses to head off to construct\n",getDescription().c_str(),m_iID).c_str());
		return;
	}

	//	Whether we let it try to be comsumed by an upgrade depends on how much spare cash we have
	int iGold = GET_PLAYER(getOwnerINLINE()).getGold();
	int iTargetGold = GET_PLAYER(getOwnerINLINE()).AI_goldTarget();

	if ( iGold > iTargetGold )
	{
		int iTryUpgradeProbability = ((iGold - iTargetGold)*100)/iGold;

		if ( GC.getGame().getSorenRandNum(100, "AI upgrade worker") < iTryUpgradeProbability )
		{
			AI_upgrade();
			if ( isDelayedDeath() )
			{
				//	Upgrade of original unit was successful
				return;
			}
		}
	}

	if ( AI_hurry(true) )
	{
		return;
	}

	if (AI_outcomeMission())
	{
		OutputDebugString(CvString::format("%S (%d) chooses to head off to do an outcome mission\n",getDescription().c_str(),m_iID).c_str());
		return;
	}

	if (!(getGroup()->canDefend()))
	{
		// Afforess - minor tweak, accounting for changes made in AI_workerNeedsDefender
		// if (GET_PLAYER(getOwnerINLINE()).AI_isPlotThreatened(plot(), 2) || (!isHuman() && AI_workerNeedsDefender(plot())))
		if ((isHuman() && GET_PLAYER(getOwnerINLINE()).AI_isPlotThreatened(plot(), 2)) || (!isHuman() && AI_workerNeedsDefender(plot())))
		{
			if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
			{
				return;
			}
		}
	}
/************************************************************************************************/
/* Afforess	                  Start		 02/17/10                                               */
/*                                                                                              */
/*           Workboats don't build Sea Tunnels over Resources                                   */
/************************************************************************************************/
	if (bCanRoute && getDomainType() != DOMAIN_SEA)
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	{
		if (plot()->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
		{
			BonusTypes eNonObsoleteBonus = plot()->getNonObsoleteBonusType(getTeam());
			if (NO_BONUS != eNonObsoleteBonus)
			{
				if (!(plot()->isConnectedToCapital()))
				{
					ImprovementTypes eImprovement = plot()->getImprovementType();
					if (NO_IMPROVEMENT != eImprovement && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
					{
						if (AI_connectPlot(plot()))
						{
							return;
						}
					}
				}
			}
		}
	}
	
	CvPlot* pBestBonusPlot = NULL;
	BuildTypes eBestBonusBuild = NO_BUILD;
	int iBestBonusValue = 0; 

    if (AI_improveBonus(25, &pBestBonusPlot, &eBestBonusBuild, &iBestBonusValue))
	{
		return;
	}

	//Afforess - scrub fallout check
	if (AI_scrubFallout())
	{
		return;
	}

	if (bCanRoute && !isBarbarian())
	{
		if (AI_connectCity())
		{
			return;
		}
	}

	// Afforess - worker financial trouble check
	if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_WORKER))
	{
		if (GC.getGameINLINE().getElapsedGameTurns() > 10 && GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble())
		{
			if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_WORKER) > (GET_PLAYER(getOwnerINLINE()).getNumCities() * 2) / 3)
			{
				if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
				{
					if (gUnitLogLevel > 2)
					{
						logBBAI("    %S's %S at (%d,%d) is disbanding itself due to large number of workers available, and financial trouble.", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE());
					}
					scrap();
					return;
				}
			}
		}
	}

	pCity = NULL;

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		pCity = plot()->getPlotCity();
		if (pCity == NULL)
		{
			pCity = plot()->getWorkingCity();
		}
	}
	
	
//	if (pCity != NULL)
//	{
//		bool bMoreBuilds = false;
//		for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
//		{
//			CvPlot* pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
//			if ((iI != CITY_HOME_PLOT) && (pLoopPlot != NULL))
//			{
//				if (pLoopPlot->getWorkingCity() == pCity)
//				{
//					if (pLoopPlot->isBeingWorked())
//					{
//						if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
//						{
//							if (pCity->AI_getBestBuildValue(iI) > 0)
//							{
//								ImprovementTypes eImprovement;
//								eImprovement = (ImprovementTypes)GC.getBuildInfo((BuildTypes)pCity->AI_getBestBuild(iI)).getImprovement();
//								if (eImprovement != NO_IMPROVEMENT)
//								{
//									bMoreBuilds = true;
//									break;
//								}
//							}
//						}
//					}
//				}
//			}
//		}
//		
//		if (bMoreBuilds)
//		{
//			if (AI_improveCity(pCity))
//			{
//				return;
//			}
//		}
//	}
	if (pCity != NULL)
	{
		if ((pCity->AI_getWorkersNeeded() > 0) && (plot()->isCity() || (pCity->AI_getWorkersNeeded() < ((1 + pCity->AI_getWorkersHave() * 2) / 3))))
		{
			if (AI_improveCity(pCity))
			{
				return;
			}
		}
	}
	
	if (AI_improveLocalPlot(2, pCity))
	{
		return;		
	}
	
	bool bBuildFort = false;
	
	if (GC.getGame().getSorenRandNum(5, "AI Worker build Fort with Priority"))
	{
		bool bCanal = ((100 * area()->getNumCities()) / std::max(1, GC.getGame().getNumCities()) < 85);
		CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
		bool bAirbase = false;
		bAirbase = (kPlayer.AI_totalUnitAIs(UNITAI_PARADROP) || kPlayer.AI_totalUnitAIs(UNITAI_ATTACK_AIR) || kPlayer.AI_totalUnitAIs(UNITAI_MISSILE_AIR));
		
		if (bCanal || bAirbase)
		{
			if (AI_fortTerritory(bCanal, bAirbase))
			{
				return;
			}
		}
		bBuildFort = true;
	}

	
	if (bCanRoute && isBarbarian())
	{
		if (AI_connectCity())
		{
			return;
		}
	}

	if ((pCity == NULL) || (pCity->AI_getWorkersNeeded() == 0) || ((pCity->AI_getWorkersHave() > (pCity->AI_getWorkersNeeded() + 1))))
	{
		if ((pBestBonusPlot != NULL) && (iBestBonusValue >= 15))
		{
			if (AI_improvePlot(pBestBonusPlot, eBestBonusBuild))
			{
				return;
			}
		}

//		if (pCity == NULL)
//		{
//			pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE()); // XXX do team???
//		}

		if (AI_nextCityToImprove(pCity))
		{
			return;
		}

		bNextCity = true;
	}

	if (pBestBonusPlot != NULL)
	{
		if (AI_improvePlot(pBestBonusPlot, eBestBonusBuild))
		{
			return;
		}
	}
		
	if (pCity != NULL)
	{
		if (AI_improveCity(pCity))
		{
			return;
		}
	}

	if (!bNextCity)
	{
		if (AI_nextCityToImprove(pCity))
		{
			return;
		}
	}

	if (bCanRoute)
	{
		if (AI_routeTerritory(true))
		{
			return;
		}

		if (AI_connectBonus(false))
		{
			return;
		}

		if (AI_routeCity())
		{
			return;
		}
	}

	if (AI_irrigateTerritory())
	{
		return;
	}
	
	if (!bBuildFort)
	{
		bool bCanal = ((100 * area()->getNumCities()) / std::max(1, GC.getGame().getNumCities()) < 85);
		CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
		bool bAirbase = false;
		bAirbase = (kPlayer.AI_totalUnitAIs(UNITAI_PARADROP) || kPlayer.AI_totalUnitAIs(UNITAI_ATTACK_AIR) || kPlayer.AI_totalUnitAIs(UNITAI_MISSILE_AIR));
		
		if (bCanal || bAirbase)
		{
			if (AI_fortTerritory(bCanal, bAirbase))
			{
				return;
			}
		}
	}
/************************************************************************************************/
/* Afforess	                  Start		 08/02/10                                               */
/*                                                                                              */
/* Fixed Borders AI                                                                             */
/************************************************************************************************/
	if (AI_StrategicForts())
	{
		return;
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	if (bCanRoute)
	{
		if (AI_routeTerritory())
		{
			return;
		}
	}

	if (!isHuman() || (isAutomated() && GET_TEAM(getTeam()).getAtWarCount(true) == 0))
	{
		if (!isHuman() || (getGameTurnCreated() < GC.getGame().getGameTurn()))
		{
			if (AI_nextCityToImproveAirlift())
			{
				return;
			}
		}
		if (!isHuman())
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/14/09                                jdog5000      */
/*                                                                                              */
/* Worker AI                                                                                    */
/************************************************************************************************/
/*
			if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY))
			{
				return;
			}
*/
			// Fill up boats which already have workers
			if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_WORKER, -1, -1, -1, -1, MOVE_SAFE_TERRITORY))
			{
				return;
			}

			// Avoid filling a galley which has just a settler in it, reduce chances for other ships
			if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY))
			{
				return;
			}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}
	
	if (AI_improveLocalPlot(3, NULL))
	{
		return;		
	}

	if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_WORKER))
	{			
		if (GC.getGameINLINE().getElapsedGameTurns() > 10)
		{
			if (GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_WORKER) > GET_PLAYER(getOwnerINLINE()).getNumCities())
			{
				if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
				{
					if (gUnitLogLevel > 2)
					{
						logBBAI("    %S's %S at (%d,%d) is disbanding itself due to large number of workers available", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE());
					}
					scrap();
					return;
				}
			}
		}
	}

	if (AI_retreatToCity(false, true))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Worker AI                                                                                    */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_barbAttackMove()
{
	PROFILE_FUNC();

	if (AI_guardCity(false, true, 1))
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      05/15/10                                jdog5000      */
/*                                                                                              */
/* Barbarian AI                                                                                 */
/************************************************************************************************/
	if (plot()->isGoody())
	{
		if (AI_anyAttack(1, 90))
		{
			return;
		}

		if (plot()->plotCount(PUF_isUnitAIType, UNITAI_ATTACK, -1, getOwnerINLINE()) == 1 && getGroup()->getNumUnits() == 1)
		{
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		

	if (GC.getGameINLINE().getSorenRandNum(2, "AI Barb") == 0)
	{
		if (AI_pillageRange(1))
		{
			return;
		}
	}

	if (AI_anyAttack(1, 20))
	{
		return;
	}	

	if (GC.getGameINLINE().isOption(GAMEOPTION_RAGING_BARBARIANS))
	{
		if (AI_pillageRange(4))
		{
			return;
		}

		if (AI_cityAttack(3, 10))
		{
			return;
		}

		if (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      05/15/10                                jdog5000      */
/*                                                                                              */
/* Barbarian AI                                                                                 */
/************************************************************************************************/
			if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, true))
			{
				return;
			}

			if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 3, true, true, true))
			{
				return;
			}
			
			if (AI_goToTargetCity(0, MAX_BARB_TARGET_CITY_RANGE))
			{
				return;
			}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		
		}
	}
	else if (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * 3))
	{
		if (AI_cityAttack(1, 15))
		{
			return;
		}

		if (AI_pillageRange(3))
		{
			return;
		}

		if (AI_cityAttack(2, 10))
		{
			return;
		}

		if (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      05/15/10                                jdog5000      */
/*                                                                                              */
/* Barbarian AI                                                                                 */
/************************************************************************************************/
			if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, true))
			{
				return;
			}

			if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 3, true, true, true))
			{
				return;
			}
			
			if (AI_goToTargetCity(0, MAX_BARB_TARGET_CITY_RANGE))
			{
				return;
			}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		
		}
	}
	else if (GC.getGameINLINE().getNumCivCities() > (GC.getGameINLINE().countCivPlayersAlive() * 2))
	{
		if (AI_pillageRange(2))
		{
			return;
		}

		if (AI_cityAttack(1, 10))
		{
			return;
		}
	}
	
	if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 1))
	{
		return;
	}

	if (AI_heal())
	{
		return;
	}

	if (AI_guardCity(false, true, 2))
	{
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_attackMove()
{
	PROFILE_FUNC();

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      05/14/10                                jdog5000      */
/*                                                                                              */
/* Unit AI, Settler AI, Efficiency                                                              */
/************************************************************************************************/
	bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));

	if ( checkSwitchToConstruct() )
	{
		return;
	}

	if ( MISSIONAI_REGROUP == getGroup()->AI_getMissionAIType() )
	{
		if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 1, true))
		{
			return;
		}
		if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, false, true))
		{
			return;
		}
	}

	if( getGroup()->getNumUnits() > 2 )
	{
		UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
		if( eGroupAI == AI_getUnitAIType() )
		{
			if( plot()->getOwnerINLINE() == getOwnerINLINE() && !bDanger )
			{
				// Shouldn't have groups of > 2 attack units
				if( getGroup()->countNumUnitAIType(UNITAI_ATTACK) > 2 )
				{
					getGroup()->AI_separate(); // will change group

					FAssert( eGroupAI == getGroup()->getHeadUnitAI() );
				}

				// Should never have attack city group lead by attack unit
				if( getGroup()->countNumUnitAIType(UNITAI_ATTACK_CITY) > 0 )
				{
					getGroup()->AI_separateAI(UNITAI_ATTACK_CITY); // will change group

					// Since ATTACK can try to joing ATTACK_CITY again, need these units to
					// take a break to let ATTACK_CITY group move and avoid hang
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}
			}
		}
	}


	// Attack choking units
	if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() && bDanger )
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( iOurDefense < 3*iEnemyOffense )
		{
			if (AI_guardCity(true))
			{
				return;
			}
		}

		if( iOurDefense > 2*iEnemyOffense )
		{
			if (AI_anyAttack(2, 55))
			{
				return;
			}
		}

		if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, false))
		{
			return;
		}

		if( iOurDefense > 2*iEnemyOffense )
		{
			if (AI_anyAttack(2, 30))
			{
				return;
			}
		}
	}

	{
		PROFILE("CvUnitAI::AI_attackMove() 1");

		// Guard a city we're in if it needs it
		if (AI_guardCity(true))
		{
			return;
		}

		//	No high priority actions to take so see if anyone requesting help
		if ( processContracts() )
		{
			return;
		}

		if( !(plot()->isOwned()) )
		{
			// Group with settler after naval drop
			//Fuyu: could result in endless loop (at least it does in AND)
			if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
			{
				return;
			}
		}

		if( !(plot()->isOwned()) || (plot()->getOwnerINLINE() == getOwnerINLINE()) )
		{
			if( area()->getCitiesPerPlayer(getOwnerINLINE()) > GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(area(), UNITAI_CITY_DEFENSE) )
			{
				// Defend colonies in new world
				if (AI_guardCity(true, true, 3))
				{
					return;
				}
			}
		}

		if (AI_heal(30, 1))
		{
			return;
		}
		
		if (!bDanger)
		{
			if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 3, true))
			{
				return;
			}

			if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 3, true))
			{
				return;
			}
		}

		if (AI_guardCityAirlift())
		{
			return;
		}

		if (AI_guardCity(false, true, 1))
		{
			return;
		}

		//join any city attacks in progress
		//	Koshling - changed this to happen unconditioanlly (used to only happen inside
		//	enemy territory) otherwise stacks massing on the borders didn't merge and reach
		//	a sufficient stack power threshold to actually start the city attack run
		if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, false, true))
		{
			return;
		}
		
		AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
        if (plot()->isCity())
        {
            if (plot()->getOwnerINLINE() == getOwnerINLINE())
            {
                if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
                {
                    if (AI_offensiveAirlift())
                    {
                        return;
                    }
                }
            }
        }
		
		if (bDanger)
		{
			if (AI_cityAttack(1, 55))
			{
				return;
			}

			if (AI_anyAttack(1, 65))
			{
				return;
			}

			if (getGroup()->hasCollateralDamage())
			{
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                               Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
				// RevolutionDCM - ranged bombardment AI
				// In theory trebs can be set to UNITAI_ATTACK
				// Dale - RB: Field Bombard START
				if (AI_RbombardUnit(1, 50, 3, 1, 120))
				{
					return;
				}
				// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                    Glider1    */
/************************************************************************************************/

				if (AI_anyAttack(1, 45, 3))
				{
					return;
				}
			}
		}

		if (!noDefensiveBonus())
		{
			if (AI_guardCity(false, false))
			{
				return;
			}
		}
		
		if (!bDanger)
		{
			if (plot()->getOwnerINLINE() == getOwnerINLINE())
			{
				bool bAssault = ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_MASSING) || (eAreaAIType == AREAAI_ASSAULT_ASSIST));
				if ( bAssault )
				{
					if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
					{
						return;
					}		
				}

				if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, -1, 1, MOVE_SAFE_TERRITORY, 3))
				{
					return;
				}

				bool bLandWar = ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
				if (!bLandWar)
				{
					// Fill transports before starting new one, but not just full of our unit ai
					if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
					{
						return;
					}

					// Pick new transport which has space for other unit ai types to join
					if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, 2, -1, -1, MOVE_SAFE_TERRITORY, 4))
					{
						return;
					}
				}

				if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0)
				{
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}
			}
		}

		// Allow larger groups if outside territory
		if( getGroup()->getNumUnits() < 3 )
		{
			if( plot()->isOwned() && GET_TEAM(getTeam()).isAtWar(plot()->getTeam()) )
			{
				if (AI_groupMergeRange(UNITAI_ATTACK, 1, true, true, true))
				{
					return;
				}
			}
		}

		if (AI_goody(3))
		{
			return;
		}

		if (AI_anyAttack(1, 70))
		{
			return;
		}
	}

	{
		PROFILE("CvUnitAI::AI_attackMove() 2");

		if (bDanger)
		{
			if (AI_pillageRange(1, 20))
			{
				return;
			}

			if (AI_cityAttack(1, 35))
			{
				return;
			}

			if (AI_anyAttack(1, 45))
			{
				return;
			}

			if (AI_pillageRange(3, 20))
			{
				return;
			}

/*************************************************************************************************/
/** BETTER_BTS_AI_MOD                      02/11/09                                jdog5000      */
/**                                                                                              */
/** Unit AI                                                                                      */
/*************************************************************************************************/
			if( getGroup()->getNumUnits() < 4 )
			{
				if (AI_choke(1))
				{
					return;
				}
			}
/*************************************************************************************************/
/** BETTER_BTS_AI_MOD                       END                                                  */
/*************************************************************************************************/

		}
	}

/*****************************************************************************************************/
/**  Author: TheLadiesOgre                                                                          **/
/**  Date: 16.09.2009                                                                               **/
/**  ModComp: TLOTags                                                                               **/
/**  Reason Added: Implement AI_paradrop for other UNITAI's now that it is potentially available    **/
/**  Notes: 14.10.2009-- Moved higher and added bCity check                                         **/
/*****************************************************************************************************/
	bool bCity = plot()->isCity();
	if (bCity)
	{
		if (AI_paradrop(getDropRange()))
		{
			return;
		}
	}

/*****************************************************************************************************/
/**  TheLadiesOgre; 16.09.2009; TLOTags                                                             **/
/*****************************************************************************************************/
	{
		PROFILE("CvUnitAI::AI_attackMove() 2");

		if (bDanger)
		{
			if (AI_cityAttack(4, 30))
			{
				return;
			}

			if (AI_anyAttack(2, 40))
			{
				return;
			}
		}

		if (!isEnemy(plot()->getTeam()))
		{
			if (AI_heal())
			{
				return;
			}
		}

/************************************************************************************************/
/* REVOLUTION_MOD                         02/11/09                                jdog5000      */
/*                                                                                              */
/* Revolution AI                                                                                */
/************************************************************************************************/
		// Change grouping rules shortly after civ creation
		if( GET_PLAYER(getOwnerINLINE()).getFreeUnitCountdown() > 0 )
		{
			if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, false, true, true))
			{
				return;
			}
		}
/************************************************************************************************/
/* REVOLUTION_MOD                          END                                                  */
/************************************************************************************************/

		if ((GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(UNITAI_CITY_DEFENSE) > 0) || (GET_TEAM(getTeam()).getAtWarCount(true) > 0))
		{
			// BBAI TODO: If we're fast, maybe shadow an attack city stack and pillage off of it

			bool bIgnoreFaster = false;
			if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
			{
				if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
				{
					bIgnoreFaster = true;
				}
			}

			if (AI_group(UNITAI_ATTACK_CITY, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 5))
			{
				return;
			}

			if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, true, true, false, /*iMaxPath*/ 4))
			{
				return;
			}
			
			// BBAI TODO: Need group to be fast, need to ignore slower groups
			//if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_FASTMOVERS))
			//{
			//	if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 4, /*iMaxOwnUnitAI*/ 1, -1, true, false, false, /*iMaxPath*/ 3))
			//	{
			//		return;
			//	}
			//}

			if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, true, false, false, /*iMaxPath*/ 1))
			{
				return;
			}
		}

		if (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
		{
			if (getGroup()->getNumUnits() > 1)
			{
				//if (AI_targetCity())
				if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, MAX_BARB_TARGET_CITY_RANGE))
				{
					return;
				}
			}
		}
		else if( area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE )
		{
			if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0)
			{
				if (getGroup()->getNumUnits() >= GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getBarbarianInitialDefenders())
				{
					if (AI_goToTargetBarbCity(10))
					{
						return;
					}
				}
			}
		}

		if (AI_guardCity(false, true, 3))
		{
			return;
		}

		if ((GET_PLAYER(getOwnerINLINE()).getNumCities() > 1) && (getGroup()->getNumUnits() == 1))
		{
			if (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE)
			{
				if (area()->getNumUnrevealedTiles(getTeam()) > 0)
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_areaMissionAIs(area(), MISSIONAI_EXPLORE, getGroup()) < (GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(area()) + 1))
					{
						if (AI_exploreRange(3))
						{
							return;
						}

						if (AI_explore())
						{
							return;
						}
					}
				}
			}
		}

		if (AI_protect(35, 5))
		{
			return;
		}

/*****************************************************************************************************/
/**  Author: TheLadiesOgre                                                                          **/
/**  Date: 16.09.2009                                                                               **/
/**  ModComp: TLOTags                                                                               **/
/**  Reason Added: Implement AI_paradrop for other UNITAI's now that it is potentially available    **/
/**  Notes: 14.10.2009-- Added bCity check                                                          **/
/*****************************************************************************************************/
		if (bCity)
		{
			if (AI_paradrop(getDropRange()))
			{
				return;
			}
		}

/*****************************************************************************************************/
/**  TheLadiesOgre; 16.09.2009; TLOTags                                                             **/
/*****************************************************************************************************/

		if (AI_offensiveAirlift())
		{
			return;
		}

		if (!bDanger && (area()->getAreaAIType(getTeam()) != AREAAI_DEFENSIVE))
		{
			if (plot()->getOwnerINLINE() == getOwnerINLINE())
			{
				if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, 1, -1, -1, 1, MOVE_SAFE_TERRITORY, 4))
				{
					return;
				}

				if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) && !(getGroup()->isHasPathToAreaEnemyCity(false)) )
				{
					if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
					{
						return;
					}
				}
			}
		}

		if (AI_defend())
		{
			return;
		}

		if (AI_travelToUpgradeCity())
		{
			return;
		}

		if( getGroup()->isStranded() )
		{
			if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
			{
				return;
			}
		}

		if( !bDanger && !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
		{
			// If no other desireable actions, wait for pickup
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}

		if( getGroup()->getNumUnits() < 4 )
		{
			if (AI_patrol())
			{
				return;
			}
		}

		if (AI_retreatToCity())
		{
			return;
		}

		if (AI_safety(3))
		{
			return;
		}
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
}


void CvUnitAI::AI_paratrooperMove()
{
	PROFILE_FUNC();

	bool bHostile = (plot()->isOwned() && isPotentialEnemy(plot()->getTeam()));
	if (!bHostile)
	{
		if (AI_guardCity(true))
		{
			return;
		}
		
		if (plot()->getTeam() == getTeam())
		{
			if (plot()->isCity())
			{
				if (AI_heal(30, 1))
				{
					return;
				}
			}
			
			AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
			bool bLandWar = ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));		
			if (!bLandWar)
			{
				if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY, 4))
				{
					return;
				}
			}
		}

		if (AI_guardCity(false, true, 1))
		{
			return;
		}
	}

	if (AI_cityAttack(1, 45))
	{
		return;
	}
	
	if (AI_anyAttack(1, 55))
	{
		return;
	}
	
	if (!bHostile)
	{
		if (AI_paradrop(getDropRange()))
		{
			return;
		}
	
		if (AI_offensiveAirlift())
		{
			return;
		}
	
		if (AI_moveToStagingCity())
		{
			return;
		}
		
		if (AI_guardFort(true))
		{
			return;
		}

		if (AI_guardCityAirlift())
		{
			return;
		}
	}

	if (getGroup()->hasCollateralDamage())
	{
		if (AI_anyAttack(1, 45, 3))
		{
			return;
		}
	}

	if (AI_pillageRange(1, 15))
	{
		return;
	}
	
	if (bHostile)
	{
		if (AI_choke(1))
		{
			return;
		}
	}
	
	if (AI_heal())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	//if (AI_protect(35))
	if (AI_protect(35, 5))
	{
		return;
	}

	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


	if (AI_safety(3))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/02/10                                jdog5000      */
/*                                                                                              */
/* War tactics AI, Barbarian AI                                                                 */
/************************************************************************************************/
void CvUnitAI::AI_attackCityMove()
{
	PROFILE_FUNC();

	if ( checkSwitchToConstruct() )
	{
		return;
	}

	AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
    bool bLandWar = !isBarbarian() && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));
	bool bAssault = !isBarbarian() && ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING));

	bool bTurtle = GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_TURTLE);
	bool bAlert1 = GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_ALERT1);
	bool bIgnoreFaster = false;
	if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
	{
		if (!bAssault && area()->getCitiesPerPlayer(getOwnerINLINE()) > 0)
		{
			bIgnoreFaster = true;
		}
	}

	bool bInCity = plot()->isCity();

	if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
	{
		// force heal if we in our own city and damaged
		// can we remove this or call AI_heal here?
		if ((getGroup()->getNumUnits() == 1) && (getDamage() > 0))
		{
			getGroup()->pushMission(MISSION_HEAL);
			return;
		}

		if( bIgnoreFaster )
		{
			// BBAI TODO: split out slow units ... will need to test to make sure this doesn't cause loops
		}

		if ((GC.getGame().getGameTurn() - plot()->getPlotCity()->getGameTurnAcquired()) <= 1)
		{
			CvSelectionGroup* pOldGroup = getGroup();

			pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);

			if (pOldGroup != getGroup())
			{
				return;
			}
		}

		if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
		{
		    if (AI_offensiveAirlift())
		    {
		        return;
		    }
		}
	}

	bool bAtWar = isEnemy(plot()->getTeam());

	bool bHuntBarbs = false;
	if (area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0 && !isBarbarian())
	{
		if ((eAreaAIType != AREAAI_OFFENSIVE) && (eAreaAIType != AREAAI_DEFENSIVE) && !bAlert1 && !bTurtle)
		{
			bHuntBarbs = true;
		}
	}

	bool bReadyToAttack = false;
	if( isBarbarian() )
	{
		bLandWar = (area()->getNumCities() - area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0);
		bReadyToAttack = (getGroup()->getNumUnits() >= 3);
	}
	else if( !bTurtle )
	{
		bReadyToAttack = ((getGroup()->getNumUnits() >= ((bHuntBarbs) ? 3 : AI_stackOfDoomExtra())));
	}

/************************************************************************************************/
/* DCM                                     04/19/09                                Johny Smith  */
/************************************************************************************************/
	// RevolutionDCM - new field bombard AI
	// Dale - RB: Field Bombard START
	//if (AI_RbombardCity())
	//{
	//	return;
	//}
	// Dale - RB: Field Bombard END

	// Dale - ARB: Archer Bombard START
	// Koshling - don't decide to do this yet if we think we're ready to
	//attack the city or we'll get distracted and just wind up Abombarding!
	bool bTriedABombard = false;

	if ( !bReadyToAttack )
	{
		if (AI_Abombard())
		{
			return;
		}

		bTriedABombard = true;
	}
	// Dale - ARB: Archer Bombard END
/************************************************************************************************/
/* DCM                                     END                                                  */
/************************************************************************************************/
	bool bCity = plot()->isCity();
	
	if( bReadyToAttack )
	{
		// Check that stack has units which can capture cities
		bReadyToAttack = false;
		int iCityCaptureCount = 0;

		CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
		while (pUnitNode != NULL && !bReadyToAttack)
		{
			CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
			pUnitNode = getGroup()->nextUnitNode(pUnitNode);

			if( !pLoopUnit->isOnlyDefensive() )
			{
				if( !(pLoopUnit->isNoCapture()) && (pLoopUnit->combatLimit() >= 100) )
				{
					iCityCaptureCount++;

					if( iCityCaptureCount > 5 || 3*iCityCaptureCount > getGroup()->getNumUnits() )
					{
						bReadyToAttack = true;
					}
				}
			}
		}

		//	Special case - if we have no attackers at all advertise for one urgently
		if ( iCityCaptureCount == 0 && !isCargo())
		{
			GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(HIGH_PRIORITY_ESCORT_PRIORITY+1,
																		   OFFENSIVE_UNITCAPABILITIES,
																		   getX_INLINE(),
																		   getY_INLINE(),
																		   this,
																		   UNITAI_ATTACK);

			if( gUnitLogLevel > 2 )
			{
				CvWString szString;
				getUnitAIString(szString, AI_getUnitAIType());
				logBBAI("    %S's %S at (%d,%d) requests initial city-capture-capable attacker for attack stack at priority %d", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE(),HIGH_PRIORITY_ESCORT_PRIORITY+1);
			}
		}
	}

	if (AI_guardCity(false, false))
	{
		if( bReadyToAttack && (eAreaAIType != AREAAI_DEFENSIVE))
		{
			CvSelectionGroup* pOldGroup = getGroup();

			pOldGroup->AI_separateNonAI(UNITAI_ATTACK_CITY);
		}

		return;
	}

	if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 0, true, true, bIgnoreFaster))
	{
		return;
	}
	
	CvCity* pTargetCity = NULL;
	if( isBarbarian() )
	{
		pTargetCity = AI_pickTargetCity(MOVE_THROUGH_ENEMY, MAX_BARB_TARGET_CITY_RANGE);
	}
	else
	{
		pTargetCity = AI_pickTargetCity(MOVE_THROUGH_ENEMY, MAX_INT, bHuntBarbs);
	}

	if( pTargetCity != NULL )
	{
		int iStepDistToTarget = stepDistance(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), getX_INLINE(), getY_INLINE());
		int iAttackRatio = std::max(100, GC.getBBAI_ATTACK_CITY_STACK_RATIO());

		//	Koshling - use the difficulty level of the opponent's settings to estimate how
		//	much more prepared we really need to be - this should cause players on higher difficulty
		//	settings to get attacked by larger stacks rather than prematurely by not-quite-adequate ones
		//	Only do this if we're still in preparation mode either in our own territory or some way away from
		//	the target (before we lose the benefit of surprise)
		if ( plot()->getOwnerINLINE() == getOwnerINLINE() || iStepDistToTarget > 3 )
		{
			int iTargetUnitTrainModifier = GC.getHandicapInfo(GET_PLAYER(pTargetCity->getOwnerINLINE()).getHandicapType()).getAITrainPercent();

			if ( iTargetUnitTrainModifier < 100 )
			{
				//	Difficulty above Noble, so a player on a higher settings
				//	Diety has 75% so squaring things means a diety player can expect to see
				//	the AI prepare attack stacks approximately 16/9 times more powerful
				//	then a noble player
				iAttackRatio *= 10000;
				iAttackRatio /= iTargetUnitTrainModifier*iTargetUnitTrainModifier;
			}
		}

		if( isBarbarian() )
		{
			iAttackRatio = std::max(80, iAttackRatio/2);
		}

		int iComparePostBombard = 0;
		// AI gets a 1-tile sneak peak to compensate for lack of memory
		if( iStepDistToTarget <= 2 || pTargetCity->isVisible(getTeam(),false) )
		{
			iComparePostBombard = getGroup()->AI_compareStacks(pTargetCity->plot(), true, true, true, std::min(2, iStepDistToTarget-1));

			/* original BBAI code
			int iDefenseModifier = pTargetCity->getDefenseModifier(true);
			int iBombardTurns = getGroup()->getBombardTurns(pTargetCity);
			iDefenseModifier *= std::max(0, 20 - iBombardTurns);
			iDefenseModifier /= 20;
			iComparePostBombard *= 100 + std::max(0, iDefenseModifier);
			iComparePostBombard /= 100; */

			// K-Mod, appart from the fact that they got the defence reduction backwards; the defense modifier 
			// is counted in AI_compareStacks. So if we add it again, we'd be double counting. 
			// In fact, it's worse than that because it would compound. 
			// I'm going to subtract defence, but unfortunately this will reduce based on the total rather than the base. 
			int iDefenseModifier = pTargetCity->getDefenseModifier(false); 
			int iBombardTurns = getGroup()->getBombardTurns(pTargetCity); 
			int iReducedModifier = iDefenseModifier; 
			iReducedModifier *= std::min(20, std::max(0, iBombardTurns - 12) + iBombardTurns/2); 
			iReducedModifier /= 20; 
			//	Koshling - changed the sign on the following calculation as it was backwards!
			//	A small reducedModifier (the effective mod we EXPECT to be fighting against very quickly)
			//	with a large raw modifier will have already had the over-large raw modifier applied
			//	(reducing the compareRatio), and that is what we are seeking to reverse, not compound!
			iComparePostBombard *= 200 - iReducedModifier + iDefenseModifier; 
			iComparePostBombard /= 200; 
			// using 200 instead of 100 to offset the over-reduction from compounding. 
			// With this, bombarding a defence bonus of 100% with reduce effective defence by 50% 

			if( iComparePostBombard < iAttackRatio && !bAtWar )
			{
				//	Koshling - if we find we are not strong enough when we get target visibility
				//	don't start a war if we haven't already.
				//	Note that this is at best a very partial fix.  Changes are needed to determine
				//	whether we are likely to have enough strength much sooner.  Things to do:
				//	1)	Add some sort of history for the last-seen defense of each city and use
				//		the most recent value as an estimatre for cities we don't yet have visibility on
				//	2)	Use stealth units to frequently regain visibility on at least the area target city
				//	3)	When evaluating city defense take into account (visible) units in the neighbourhood
				//		which are not actually in the city itself - EDIT (3) now DONE
				bReadyToAttack = false;	//	Force it to gather more units first
			}
		}

		//	Grab some more units if we can
		CvUnitSelectionCriteria healerCriteria;

		healerCriteria.m_bIsHealer = true;

		//	Try to get a healer if we don't have one
		if ( !isCargo() && !getGroup()->meetsUnitSelectionCriteria(&healerCriteria) )
		{
			GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(HIGH_PRIORITY_ESCORT_PRIORITY,
																		   DEFENSIVE_UNITCAPABILITIES,
																		   getX_INLINE(),
																		   getY_INLINE(),
																		   this,
																		   UNITAI_RESERVE,
																		   -1,
																		   &healerCriteria);

			if( gUnitLogLevel > 2 )
			{
				CvWString szString;
				getUnitAIString(szString, AI_getUnitAIType());
				logBBAI("    %S's %S at (%d,%d) requests healer for attack stack", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE());
			}
		}

		//	If we're still on home turf advertise for more attackers at a
		//	priority that is increased if we're not yet up to strength
		if ( plot()->getOwnerINLINE() == getOwnerINLINE() && !isCargo() )
		{
			GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(bReadyToAttack ? LOW_PRIORITY_ESCORT_PRIORITY : HIGH_PRIORITY_ESCORT_PRIORITY,
																		   OFFENSIVE_UNITCAPABILITIES,
																		   getX_INLINE(),
																		   getY_INLINE(),
																		   this,
																		   UNITAI_ATTACK);

			if( gUnitLogLevel > 2 )
			{
				CvWString szString;
				getUnitAIString(szString, AI_getUnitAIType());
				logBBAI("    %S's %S at (%d,%d) requests more attackers for attack stack at priority %d", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE(),bReadyToAttack ? LOW_PRIORITY_ESCORT_PRIORITY : HIGH_PRIORITY_ESCORT_PRIORITY);
			}

			//	Also try to get a great commander if we don't have one
			if ( GC.getGameINLINE().isOption(GAMEOPTION_GREAT_COMMANDERS) && !getGroup()->hasCommander() )
			{
				GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(bReadyToAttack ? HIGH_PRIORITY_ESCORT_PRIORITY : LOW_PRIORITY_ESCORT_PRIORITY,
																			   NO_UNITCAPABILITIES,
																			   getX_INLINE(),
																			   getY_INLINE(),
																			   this,
																			   UNITAI_GENERAL);

				if( gUnitLogLevel > 2 )
				{
					CvWString szString;
					getUnitAIString(szString, AI_getUnitAIType());
					logBBAI("    %S's %S at (%d,%d) requests great commander for attack stack at priority %d", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE(), HIGH_PRIORITY_ESCORT_PRIORITY);
				}
			}
		}
		
		if( iStepDistToTarget <= 2 )
		{
			if( iComparePostBombard < iAttackRatio )
			{
				if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
				{
					return;
				}

				int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),1,false,false,true);
				int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pTargetCity->plot(),2,false,false);

				// If in danger, seek defensive ground
				if( 4*iOurOffense < 3*iEnemyOffense )
				{
					if( AI_choke(1, true) )
					{
						return;
					}
				}
			}

			if (iStepDistToTarget == 1)
			{
				// If next to target city and we would attack after bombarding down defenses,
				// or if defenses have crept up past half
				if( (iComparePostBombard >= iAttackRatio) || (pTargetCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 1) / 2)) )
				{
					if( (iComparePostBombard < std::max(150, GC.getDefineINT("BBAI_SKIP_BOMBARD_MIN_STACK_RATIO"))) && pTargetCity->isDirectAttackable() )
					{
						// Move to good tile to attack from unless we're way more powerful
						if( AI_goToTargetCity(0,1,pTargetCity) )
						{
							return;
						}
					}

					// Bombard may skip if stack is powerful enough
					if (AI_bombardCity())
					{
						return;
					}

					//stack attack
					if (getGroup()->getNumUnits() > 1)
					{ 
						// BBAI TODO: What is right ratio?
						if (AI_stackAttackCity(1, iAttackRatio, true))
						{
							return;
						}
					}

					// If not strong enough alone, merge if another stack is nearby
					if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
					{
						return;
					}
					
					if( getGroup()->getNumUnits() == 1 )
					{
						if( AI_cityAttack(1, 50) )
						{
							return;
						}
					}
				}
			}

/*****************************************************************************************************/
/**  Author: TheLadiesOgre                                                                          **/
/**  Date: 16.09.2009                                                                               **/
/**  ModComp: TLOTags                                                                               **/
/**  Reason Added: Implement AI_paradrop for other UNITAI's now that it is potentially available    **/
/**  Notes: 14.10.2009-- Moved higher and added bCity check                                         **/
/*****************************************************************************************************/
			if (bCity)
			{
				if (AI_paradrop(getDropRange()))
				{
					return;
				}
			}

/*****************************************************************************************************/
/**  TheLadiesOgre; 16.09.2009; TLOTags                                                             **/
/*****************************************************************************************************/

			if( iComparePostBombard < iAttackRatio)
			{
				// If not strong enough, pillage around target city without exposing ourselves
				if( AI_pillageRange(1) )
				{
					return;
				}
				
				if( AI_anyAttack(1, 60, 0, false) )
				{
					return;
				}

				if (AI_heal(((iComparePostBombard*100)/iAttackRatio >= 80) ? 0 : 30, 1))
				{
					return;
				}

				// Pillage around enemy city
				if( AI_pillageAroundCity(pTargetCity, 11, 3) )
				{
					return;
				}

				if( AI_pillageAroundCity(pTargetCity, 0, 5) )
				{
					return;
				}

				if( AI_choke(1) )
				{
					return;
				}
			}
			else
			{
				if( AI_goToTargetCity(0,4,pTargetCity) )
				{
					return;
				}
			}
		}
	}

	// Koshling - if we haven't found any higher priority action try Abombard now
	if ( !bTriedABombard && AI_Abombard())
	{
		return;
	}

	if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 2, true, true, bIgnoreFaster))
	{
		return;
	}

	if (AI_heal(30, 1))
	{
		return;
	}

	// BBAI TODO: Stack v stack combat ... definitely want to do in own territory, but what about enemy territory?
	if (getGroup()->hasCollateralDamage() && plot()->getOwnerINLINE() == getOwnerINLINE())
	{
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		// RevolutionDCM - ranged bombardment AI
		// Dale - RB: Field Bombard START
		if (AI_RbombardUnit(1, 50, 3, 2, 130))
		{
			return;
		}
		// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                     Glider1    */
/************************************************************************************************/
		
		if (AI_anyAttack(1, 45, 3, false))
		{
			return;
		}

		if( !bReadyToAttack )
		{
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
			// RevolutionDCM - ranged bombardment AI
			// Dale - RB: Field Bombard START
			if (AI_RbombardUnit(getDCMBombRange(), 30, 5, 2, 110))
			{
				return;
			}
			// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                     Glider1    */
/************************************************************************************************/
			
			if (AI_anyAttack(1, 25, 5))
			{
				return;
			}
			// K-Mod; sometimes you just need to blast them with collateral damage before they can do it to you!
			// ... and please don't let them wipe out a massive stack just because we were too scared to fight back

			// look. I don't want to spend too much time messing around with this. So let me just try an experimental heuristic... 
			if (getGroup()->getNumUnits() > 1 && AI_anyAttack(1, 60 / (getGroup()->getNumUnits() + 1), 3 + getGroup()->getNumUnits(), false))
			{
				return;
			}
		}
	}

	//	If we're still in our own territory attack infiltrators
	if (plot()->getOwnerINLINE() == getOwnerINLINE() && AI_anyAttack(2, 50) )
	{
		return;
	}
	else if (AI_anyAttack(1, 60, 0, false))
	{
		return;
	}

	if (bAtWar && (getGroup()->getNumUnits() <= 2))
	{
		if (AI_pillageRange(3, 11))
		{
			return;
		}

		if (AI_pillageRange(1))
		{
			return;
		}
	}

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		if (!bLandWar)
		{
			if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
			{
				return;
			}
		}

		if( bReadyToAttack )
		{
			// Wait for units about to join our group
			MissionAITypes eMissionAIType = MISSIONAI_GROUP;
			int iJoiners = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
			
			if( (iJoiners*5) > getGroup()->getNumUnits() )
			{
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}
		}
		else
		{
			if( !isBarbarian() && (eAreaAIType == AREAAI_DEFENSIVE) )
			{
				// Use smaller attack city stacks on defense
				if (AI_guardCity(false, true, 3))
				{
					return;
				}
			}

			if( bTurtle )
			{
				if (AI_guardCity(false, true, 7))
				{
					return;
				}
			}

			int iTargetCount = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
			if ((iTargetCount * 5) > getGroup()->getNumUnits())
			{
				MissionAITypes eMissionAIType = MISSIONAI_GROUP;
				int iJoiners = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
				
				if( (iJoiners*5) > getGroup()->getNumUnits() || isBarbarian())
				{
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}

				if (AI_moveToStagingCity())
				{
					return;
				}
			}
		}
	}

	if (AI_heal(50, 3))
	{
		return;
	}

	if (!bAtWar)
	{
		if (AI_heal())
		{
			return;
		}

		if ((getGroup()->getNumUnits() == 1) && (getTeam() != plot()->getTeam()))
		{
			if (AI_retreatToCity())
			{
				return;
			}
		}
	}

	if (!bReadyToAttack && !noDefensiveBonus())
	{
		if (AI_guardCity(false, false))
		{
			return;
		}
	}

	bool bAnyWarPlan = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);

	if (bReadyToAttack)
	{
		if( isBarbarian() )
		{
			if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, MAX_BARB_TARGET_CITY_RANGE))
			{
				return;
			}

			if (AI_pillageRange(3, 11))
			{
				return;
			}

			if (AI_pillageRange(1))
			{
				return;
			}
		}
		else if (bHuntBarbs && AI_goToTargetBarbCity((bAnyWarPlan ? 7 : 12)))
		{
			return;
		}
		else if (bLandWar && pTargetCity != NULL)
		{
			// Before heading out, check whether to wait to allow unit upgrades
			if( bInCity && plot()->getOwnerINLINE() == getOwnerINLINE() )
			{
				if( !(GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble()) )
				{
					// Check if stack has units which can upgrade
					int iNeedUpgradeCount = 0;

					CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
					while (pUnitNode != NULL)
					{
						CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
						pUnitNode = getGroup()->nextUnitNode(pUnitNode);

						if( pLoopUnit->getUpgradeCity(false) != NULL )
						{
							iNeedUpgradeCount++;

							if( 8*iNeedUpgradeCount > getGroup()->getNumUnits() )
							{
								getGroup()->pushMission(MISSION_SKIP);
								return;
							}
						}
					}
				}
			}

			if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 5, pTargetCity))
			{
				return;
			}

			if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 2, 2))
			{
				return;
			}

			if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 8, pTargetCity))
			{
				return;
			}

			// Load stack if walking will take a long time
			if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 3))
			{
				return;
			}

			if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, 12, pTargetCity))
			{
				return;
			}

			if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4, 7))
			{
				return;
			}

			if (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2, MAX_INT, pTargetCity))
			{
				return;
			}

			if (bAnyWarPlan)
			{
				CvCity* pTargetCity = area()->getTargetCity(getOwnerINLINE());

				if (pTargetCity != NULL)
				{
					if (AI_solveBlockageProblem(pTargetCity->plot(), (GET_TEAM(getTeam()).getAtWarCount(true) == 0)))
					{
						return;
					}
				}
			}
		}
	}
	else
	{
		int iTargetCount = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP);
		if( ((iTargetCount * 4) > getGroup()->getNumUnits()) || ((getGroup()->getNumUnits() + iTargetCount) >= (bHuntBarbs ? 3 : AI_stackOfDoomExtra())) )
		{
			MissionAITypes eMissionAIType = MISSIONAI_GROUP;
			int iJoiners = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 2);
			
			if( (iJoiners*6) > getGroup()->getNumUnits() )
			{
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}

		if (getGroup()->hasBombardCapability() && noDefensiveBonus())
		{
			// BBAI Notes: Add this stack lead by bombard unit to stack probably not lead by a bombard unit
			// BBAI TODO: Some sense of minimum stack size?  Can have big stack moving 10 turns to merge with tiny stacks
			if (AI_group(UNITAI_ATTACK_CITY, -1, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ true))
			{
				return;
			}
		}
		else
		{
			if (AI_group(UNITAI_ATTACK_CITY, AI_stackOfDoomExtra() * 2, -1, -1, bIgnoreFaster, true, true, /*iMaxPath*/ 10, /*bAllowRegrouping*/ false))
			{
				return;
			}
		}
	}

	if (plot()->getOwnerINLINE() == getOwnerINLINE() && bLandWar)
	{
		if( (GET_TEAM(getTeam()).getAtWarCount(true) > 0) )
		{
			// if no land path to enemy cities, try getting there another way
			if (AI_offensiveAirlift())
			{
				return;
			}

			if( pTargetCity == NULL )
			{
				if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
				{
					return;
				}
			}
		}
	}

	if (!isBarbarian() && AI_moveToStagingCity())
	{
		return;
	}

	if (AI_offensiveAirlift())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}

		if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
		{
			// If no other desireable actions, wait for pickup
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}

		if (AI_patrol())
		{
			return;
		}
	}

	if (AI_safety(3))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


void CvUnitAI::AI_attackCityLemmingMove()
{
	if (AI_cityAttack(1, 80)) 
	{ 
		return; 
	} 

	if (AI_bombardCity())
	{ 
		return; 
	} 

	if (AI_cityAttack(1, 40)) 
	{ 
		return; 
	} 

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/29/10                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if (AI_goToTargetCity(MOVE_THROUGH_ENEMY))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{ 
		return; 
	} 

	if (AI_anyAttack(1, 70)) 
	{ 
		return; 
	} 

	if (AI_anyAttack(1, 0)) 
	{ 
		return; 
	} 

	getGroup()->pushMission(MISSION_SKIP);
}


void CvUnitAI::AI_collateralMove()
{
	PROFILE_FUNC();
	
	if (AI_leaveAttack(1, 20, 100))
	{
		return;
	}

	if (AI_guardCity(false, true, 1))
	{
		return;
	}

	if (AI_heal(30, 1))
	{
		return;
	}

	if (AI_cityAttack(1, 35))
	{
		return;
	}

/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment AI
	// Dale - RB: Field Bombard START
	if (AI_RbombardUnit(1, 50, 3, 1, 100))
	{
		return;
	}
	// RevolutionDCM - end	
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                     Glider1    */
/************************************************************************************************/
	
	if (AI_anyAttack(1, 45, 3))
	{
		return;
	}

	if (AI_anyAttack(1, 55, 2))
	{
		return;
	}
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment AI
	// Dale - RB: Field Bombard START
	if (AI_RbombardUnit(1, 40, 3, 0, 100))
	{
		return;
	}
	// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                    Glider1    */
/************************************************************************************************/

	if (AI_anyAttack(1, 35, 3))
	{
		return;
	}

	if (AI_anyAttack(1, 30, 4))
	{
		return;
	}
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment AI
	// Dale - RB: Field Bombard START
	if (AI_RbombardUnit(1, 25, 5, 0, 80))
	{
		return;
	}
	// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                              END                                    Glider1    */
/************************************************************************************************/
	if (AI_anyAttack(1, 20, 5))
	{
		return;
	}

	if (AI_heal())
	{
		return;
	}

	if (!noDefensiveBonus())
	{
		if (AI_guardCity(false, false))
		{
			return;
		}
	}
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment AI
	// Dale - RB: Field Bombard START
	if (AI_RbombardUnit(getDCMBombRange(), 40, 3, 0, 100))
	{
		return;
	}
	// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                     Glider1    */
/************************************************************************************************/

	if (AI_anyAttack(2, 55, 3))
	{
		return;
	}

	if (AI_cityAttack(2, 50))
	{
		return;
	}

	if (AI_anyAttack(2, 60))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	//if (AI_protect(50))
	if (AI_protect(50, 8))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		return;
	}
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment plot AI
	// Dale - RB: Field Bombard START
	if (AI_RbombardPlot(getDCMBombRange(), 20))
	{
		return;
	}
	// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                     Glider1    */
/************************************************************************************************/

	if (AI_guardCity(false, true, 3))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety(3))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_pillageMove()
{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/05/10                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	PROFILE_FUNC();

	if (AI_guardCity(false, true, 1))
	{
		return;
	}

	if (AI_heal(30, 1))
	{
		return;
	}

	// BBAI TODO: Shadow ATTACK_CITY stacks and pillage

	//join any city attacks in progress
	if ( MISSIONAI_REGROUP == getGroup()->AI_getMissionAIType() || (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE()))
	{
		if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, false, true))
		{
			return;
		}
	}
	
	if (AI_cityAttack(1, 55))
	{
		return;
	}

	if (AI_anyAttack(1, 65))
	{
		return;
	}

	if (!noDefensiveBonus())
	{
		if (AI_guardCity(false, false))
		{
			return;
		}
	}

/*****************************************************************************************************/
/**  Author: TheLadiesOgre                                                                          **/
/**  Date: 16.09.2009                                                                               **/
/**  ModComp: TLOTags                                                                               **/
/**  Reason Added: Implement AI_paradrop for other UNITAI's now that it is potentially available    **/
/**  Notes: 14.10.2009-- Added bCity check                                                          **/
/*****************************************************************************************************/
	bool bCity = plot()->isCity();
	if (bCity)
	{
		if (AI_paradrop(getDropRange()))
		{
			return;
		}
	}

/*****************************************************************************************************/
/**  TheLadiesOgre; 16.09.2009; TLOTags                                                             **/
/*****************************************************************************************************/
	if (AI_pillageRange(3, 11))
	{
		return;
	}
	
	if (AI_choke(1))
	{
		return;
	}

	if (AI_pillageRange(1))
	{
		return;
	}

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
		{
			return;
		}
	}

	if (AI_heal(50, 3))
	{
		return;
	}

	if (!isEnemy(plot()->getTeam()))
	{
		if (AI_heal())
		{
			return;
		}
	}

	if (AI_group(UNITAI_PILLAGE, /*iMaxGroup*/ 1, /*iMaxOwnUnitAI*/ 1, -1, /*bIgnoreFaster*/ true, false, false, /*iMaxPath*/ 3))
	{
		return;
	}

	if ((area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) || isEnemy(plot()->getTeam()))
	{
		if (AI_pillage(20))
		{
			return;
		}
	}

	if (AI_heal())
	{
		return;
	}

	if (AI_guardCity(false, true, 3))
	{
		return;
	}

	if (AI_offensiveAirlift())
	{
		return;
	}

	if (AI_travelToUpgradeCity())
	{
		return;
	}

	if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
	{
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety(3))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
}

void CvUnitAI::AI_reserveMove()
{
	PROFILE_FUNC();

	if ( checkSwitchToConstruct() )
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	//bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3) > 0);
	bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (bDanger && AI_leaveAttack(2, 55, 130))
	{
		return;
	}
	
	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
		{
			return;
		}
		if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_WORKER, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
		{
			return;
		}
	}

	//	No high priority actions to take so see if anyone requesting help
	if ( processContracts() )
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/
	if( !(plot()->isOwned()) )
	{
		if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 1, true))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	
	if (AI_guardCity(true))
	{
		return;
	}

	if (!bDanger)
	{
		if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 3, true))
		{
			return;
		}
	}
	
	if (!noDefensiveBonus())
	{
		if (AI_guardFort(false))
		{
			return;
		}

		//Afforess - Fixed Borders AI
		if (canClaimTerritory(NULL) && getGroup()->getNumUnits() == 1)
		{
			if (AI_guardClaimedResource())
			{
				return;
			}

#ifdef USE_REACHABLE_ENUMERATION
			CvReachablePlotSet plotSet(getGroup(), MOVE_THROUGH_ENEMY, 12);
			if (AI_claimResources(&plotSet, 0, AI_searchRange(12)))
#else
			if (AI_claimResources(0, AI_searchRange(8)))
#endif
			{
				return;
			}
		}
		m_bClaimedTerritory = false;
		//Afforess - Fixed Borders AI
	}
		
	if (AI_guardCityAirlift())
	{
		return;
	}

	if (AI_guardCity(false, true, 1))
	{
		return;
	}
	
	if (AI_guardCitySite())
	{
		return;
	}
	
	if (!noDefensiveBonus())
	{
		if (AI_guardFort(true))
		{
			return;
		}
		
		if (AI_guardBonus(15))
		{
			return;
		}
	}

	if (AI_heal(30, 1))
	{
		return;
	}

	if (bDanger)
	{
		if (AI_cityAttack(1, 55))
		{
			return;
		}

		if (AI_anyAttack(1, 60))
		{
			return;
		}
	}

	if (!noDefensiveBonus())
	{
		if (AI_guardCity(false, false))
		{
			return;
		}
	}
	
	if (bDanger)
	{
		if (AI_cityAttack(3, 45))
		{
			return;
		}

		if (AI_anyAttack(3, 50))
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	//if (AI_protect(45))
	if (AI_protect(45, 8))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		return;
	}

	if (AI_guardCity(false, true, 3))
	{
		return;
	}

	if (AI_defend())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety(3))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_pillageCounterMove()
{
	PROFILE_FUNC();

	//	For now
	AI_counterMove();
}

void CvUnitAI::AI_counterMove()
{
	PROFILE_FUNC();

	if ( checkSwitchToConstruct() )
	{
		return;
	}

	if ( MISSIONAI_REGROUP == getGroup()->AI_getMissionAIType() )
	{
		if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 1, true))
		{
			return;
		}
		if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, false, true))
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/03/10                                jdog5000      */
/*                                                                                              */
/* Unit AI, Settler AI                                                                          */
/************************************************************************************************/
	// Should never have group lead by counter unit
	if( getGroup()->getNumUnits() > 1 )
	{
		UnitAITypes eGroupAI = getGroup()->getHeadUnitAI();
		if( eGroupAI == AI_getUnitAIType() )
		{
			if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
			{
				//FAssert(false); // just interested in when this happens, not a problem
				getGroup()->AI_separate(); // will change group
				return;
			}
		}
	}

	if( !(plot()->isOwned()) )
	{
		 //Fuyu: could result in endless loop (at least it does in AND)
		if( AI_groupMergeRange(UNITAI_SETTLE, 2, true, false, false) )
		{
			return;
		}
	}

	if (AI_guardCity(false, true, 1))
	{
		return;
	}
	
	if (getSameTileHeal() > 0)
	{
		if (!canAttack())
		{
			// Don't restrict to groups carrying cargo ... does this apply to any units in standard bts anyway?
			if (AI_shadow(UNITAI_ATTACK_CITY, -1, 21, false, false, 4))
			{
				return;
			}
		}
	}

	bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
	AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		if( !bDanger )
		{
			if (plot()->isCity())
			{
				if ((eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST))
				{
					if (AI_offensiveAirlift())
					{
						return;
					}
				}
			}
		
			if( (eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) || (eAreaAIType == AREAAI_ASSAULT_MASSING) )
			{
				if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
				{
					return;
				}

				if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
				{
					return;
				}
			}
		}

		if (!noDefensiveBonus())
		{
			if (AI_guardCity(false, false))
			{
				return;
			}

			//Afforess - Fixed Borders AI
			if (canClaimTerritory(NULL) && getGroup()->getNumUnits() == 1)
			{
				if (AI_guardClaimedResource())
				{
					return;
				}

#ifdef USE_REACHABLE_ENUMERATION
				CvReachablePlotSet plotSet(getGroup(), MOVE_THROUGH_ENEMY, 12);
				if (AI_claimResources(&plotSet, 0, AI_searchRange(12)))
#else
				if (AI_claimResources(0, AI_searchRange(8)))
#endif
				{
					return;
				}
				m_bClaimedTerritory = false;
			}
			//Afforess - Fixed Borders AI
		}
	}

	//	No high priority actions to take so see if anyone requesting help
	if ( processContracts() )
	{
		return;
	}

	//join any city attacks in progress
	if (plot()->getOwnerINLINE() != getOwnerINLINE())
	{
		if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
		{
			return;
		}
	}

	if (bDanger)
	{
		if (AI_cityAttack(1, 35))
		{
			return;
		}

		if (AI_anyAttack(1, 40))
		{
			return;
		}
	}
	
	bool bIgnoreFasterStacks = false;
	if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
	{
		if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
		{
			bIgnoreFasterStacks = true;
		}
	}

	if (AI_group(UNITAI_ATTACK_CITY, /*iMaxGroup*/ -1, 2, -1, bIgnoreFasterStacks, /*bIgnoreOwnUnitType*/ true, /*bStackOfDoom*/ true, /*iMaxPath*/ 6))
	{
		return;
	}
	
	bool bFastMovers = (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_FASTMOVERS));

	if (AI_group(UNITAI_ATTACK, /*iMaxGroup*/ 2, -1, -1, bFastMovers, /*bIgnoreOwnUnitType*/ true, /*bStackOfDoom*/ true, /*iMaxPath*/ 5))
	{
		return;
	}

	// BBAI TODO: merge with nearby pillage
	
	if (AI_guardCity(false, true, 3))
	{
		return;
	}

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		if( !bDanger )
		{
			if( (eAreaAIType != AREAAI_DEFENSIVE) )
			{
				if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
				{
					return;
				}

				if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK, -1, -1, -1, -1, MOVE_SAFE_TERRITORY, 4))
				{
					return;
				}
			}
		}
	}

	if (AI_heal())
	{
		return;
	}

	if (AI_offensiveAirlift())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety(3))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
}


void CvUnitAI::AI_cityDefenseMove()
{
	PROFILE_FUNC();

	if ( checkSwitchToConstruct() )
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	//bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3) > 0);
	bool bDanger = (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 3));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/

	if ( MISSIONAI_REGROUP == getGroup()->AI_getMissionAIType() )
	{
		if (AI_group(UNITAI_SETTLE, 2, -1, -1, false, false, false, 1, true))
		{
			return;
		}
		if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, false, true))
		{
			return;
		}
	}
	else if( !(plot()->isOwned()) )
	{
		if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 2, true))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (bDanger)
	{
		//	Never remove the last unit from the city
		if (plot()->getPlotCity() == NULL || plot()->plotCount(PUF_canDefend /*PUF_canDefendGroupHead*/, -1, -1, getOwnerINLINE()) != getGroup()->getNumUnits()) // XXX check for other team's units?
		{
			if (AI_leaveAttack(1, 70, 175))
			{
				return;
			}

			if (AI_chokeDefend())
			{
				return;
			}
		}
	}

/************************************************************************************************/
/* DCM                                     04/19/09                                Johny Smith  */
/************************************************************************************************/
	// RevolutionDCM - new field bombard AI
	// Dale - RB: Field Bombard START
	//if (AI_RbombardCity())
	//{
	//	return;
	//}
	// Dale - RB: Field Bombard END

	// Dale - ARB: Archer Bombard START
	if (AI_Abombard())
	{
		return;
	}
	// Dale - ARB: Archer Bombard END
/************************************************************************************************/
/* DCM                                     END                                                  */
/************************************************************************************************/
	if (AI_guardCityBestDefender())
	{
		return;
	}
	
	if (!bDanger)
	{
		if (plot()->getOwnerINLINE() == getOwnerINLINE())
		{
			if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY, 1))
			{
				return;
			}
		}
	}
	
	if (AI_guardCityMinDefender(false))
	{
		return;
	}

	//Afforess - Fixed Borders AI start
	if (canClaimTerritory(NULL) && getGroup()->getNumUnits() == 1)
	{
		if (AI_guardClaimedResource())
		{
			return;
		}

#ifdef USE_REACHABLE_ENUMERATION
		CvReachablePlotSet plotSet(getGroup(), MOVE_THROUGH_ENEMY, 8);
		if (AI_claimResources(&plotSet, 0, AI_searchRange(8)))
#else
		if (AI_claimResources(0, AI_searchRange(8)))
#endif
		{
			return;
		}
		m_bClaimedTerritory = false;
	}
	//Afforess - Fixed Borders AI end

	if (AI_guardCity(true))
	{
		return;
	}

	//	No high priority actions to take so see if anyone requesting help
	if ( processContracts() )
	{
		return;
	}
	
	if (!bDanger)
	{
		if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 1, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
		{
			return;
		}

		if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 2, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
		{
			return;
		}

		if (plot()->getOwnerINLINE() == getOwnerINLINE())
		{
			if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, -1, -1, 1, -1, MOVE_SAFE_TERRITORY))
			{
				return;
			}
		}
	}
	
	AreaAITypes eAreaAI = area()->getAreaAIType(getTeam());
	if ((eAreaAI == AREAAI_ASSAULT) || (eAreaAI == AREAAI_ASSAULT_MASSING) || (eAreaAI == AREAAI_ASSAULT_ASSIST))
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
		{
			return;
		}		
	}

	if ((AI_getBirthmark() % 4) == 0)
	{
		if (AI_guardFort())
		{
			return;
		}
	}

	if (AI_guardCityAirlift())
	{
		return;
	}

	if (AI_guardCity(false, true, 1))
	{
		return;
	}

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 3, -1, -1, -1, MOVE_SAFE_TERRITORY))
		{
			// will enter here if in danger
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/02/10                                jdog5000      */
/*                                                                                              */
/* City AI                                                                                      */
/************************************************************************************************/
	//join any city attacks in progress
	if (plot()->getOwnerINLINE() != getOwnerINLINE())
	{
		if (AI_groupMergeRange(UNITAI_ATTACK_CITY, 1, true, true))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_guardCity(false, true))
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/04/10                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if (!isBarbarian() && ((area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) || (area()->getAreaAIType(getTeam()) == AREAAI_MASSING)))
	{
		bool bIgnoreFaster = false;
		if (GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_LAND_BLITZ))
		{
			if (area()->getAreaAIType(getTeam()) != AREAAI_ASSAULT)
			{
				bIgnoreFaster = true;
			}
		}

		if (AI_group(UNITAI_ATTACK_CITY, -1, 2, 4, bIgnoreFaster))
		{
			return;
		}
	}
	
	if (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT)
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, UNITAI_ATTACK_CITY, 2, -1, -1, 1, MOVE_SAFE_TERRITORY))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	//	Ok, we're not needed locally - try to group up with others nearby
	//	if we're not already in a city (preparatory to us all moving to one)
	if ( plot()->getPlotCity() == NULL )
	{
		if (AI_groupMergeRange(UNITAI_CITY_DEFENSE,3,false,true) ||
			AI_groupMergeRange(UNITAI_CITY_COUNTER,3,false,true))
		{
			return;
		}

		if (AI_retreatToCity())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_cityDefenseExtraMove()
{
	PROFILE_FUNC();

	CvCity* pCity;

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/
	if( !(plot()->isOwned()) )
	{
		if (AI_group(UNITAI_SETTLE, 1, -1, -1, false, false, false, 1, true))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_leaveAttack(2, 55, 150))
	{
		return;
	}
	
	if (AI_chokeDefend())
	{
		return;
	}
/************************************************************************************************/
/* DCM                                     04/19/09                                Johny Smith  */
/************************************************************************************************/
	// RevolutionDCM - new field bombard ai
	// Dale - RB: Field Bombard START
	//if (AI_RbombardCity())
	//{
	//	return;
	//}
	// Dale - RB: Field Bombard END

	// Dale - ARB: Archer Bombard START
	if (AI_Abombard())
	{
		return;
	}
	// Dale - ARB: Archer Bombard END
/************************************************************************************************/
/* DCM                                     END                                                  */
/************************************************************************************************/
	if (AI_guardCityBestDefender())
	{
		return;
	}

	if (AI_guardCity(true))
	{
		return;
	}

	if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 1, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
	{
		return;
	}

	if (AI_group(UNITAI_SETTLE, /*iMaxGroup*/ 2, -1, -1, false, false, false, /*iMaxPath*/ 2, /*bAllowRegrouping*/ true))
	{
		return;
	}

	//	No high priority actions to take so see if anyone requesting help
	if ( processContracts() )
	{
		return;
	}

	pCity = plot()->getPlotCity();

	if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE())) // XXX check for other team?
	{
		if (plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isUnitAIType, AI_getUnitAIType()) == 1)
		{
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}

	if (AI_guardCityAirlift())
	{
		return;
	}

	if (AI_guardCity(false, true, 1))
	{
		return;
	}

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		if (AI_load(UNITAI_SETTLER_SEA, MISSIONAI_LOAD_SETTLER, UNITAI_SETTLE, 3, -1, -1, -1, MOVE_SAFE_TERRITORY, 3))
		{
			return;
		}
	}

	if (AI_guardCity(false, true))
	{
		return;
	}

	//	Ok, we're not needed locally - try to group up with others nearby
	//	if we're not already in a city (preparatory to us all moving to one)
	if ( plot()->getPlotCity() == NULL )
	{
		if (AI_groupMergeRange(UNITAI_CITY_COUNTER,3,false,true) ||
			AI_groupMergeRange(UNITAI_CITY_DEFENSE,3,false,true))
		{
			return;
		}

		if (AI_retreatToCity())
		{
			return;
		}
	}

	if (AI_safety(3))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_exploreMove()
{
	PROFILE_FUNC();

	if (!isHuman() && canAttack())
	{
		if (AI_cityAttack(1, 60))
		{
			return;
		}

		if (AI_anyAttack(1, 70))
		{
			OutputDebugString(CvString::format("%S (%d) chooses to attack\n",getDescription().c_str(),m_iID).c_str());
			return;
		}
	}
/************************************************************************************************/
/* Afforess	                  Start		 06/20/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
/*
	if (getDamage() > 0)
	{
		if ((plot()->getFeatureType() == NO_FEATURE) || (GC.getFeatureInfo(plot()->getFeatureType()).getTurnDamage() == 0))
		{
			getGroup()->pushMission(MISSION_HEAL);
			return;
		}
	}
*/
	if (getDamage() > 0)
	{
		OutputDebugString(CvString::format("%S (%d) damaged at (%d,%d)...\n",getDescription().c_str(),m_iID,m_iX,m_iY).c_str());
		//	If there is an adjacent enemy seek safety before we heal
		if ( exposedToDanger(plot(), 80) )
		{
			OutputDebugString("    ...plot is dangerous - seeking safety\n");
			if ( AI_safety() )
			{
				return;
			}
		}

		if (plot()->getTotalTurnDamage(this) <= 0)
		{
			OutputDebugString(CvString::format("    ...healing at (%d,%d)\n",m_iX,m_iY).c_str());
			getGroup()->pushMission(MISSION_HEAL);
			return;
		}
		else if ( getDamage() > 25 )
		{
			//	Look for somewhere safer
			if ( AI_safety(3) )
			{
				return;
			}
		}
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/


	if (!isHuman())
	{
		if (AI_pillageRange(1))
		{
			return;
		}

		if (AI_cityAttack(3, 80))
		{
			return;
		}
	}

	if (AI_goody(4))
	{
		OutputDebugString(CvString::format("%S (%d) chooses to go for goody\n",getDescription().c_str(),m_iID).c_str());
		return;
	}

	if (AI_exploreRange(3))
	{
		return;
	}

	if( gUnitLogLevel > 2 )
	{
		CvWString szString;
		getUnitAIString(szString, AI_getUnitAIType());
		logBBAI("    %S's %S at (%d,%d) finds nothing nearby as exploration target", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE());
	}

	if (!isHuman())
	{
		if (AI_pillageRange(3))
		{
			return;
		}
	}

	if (AI_explore())
	{
		return;
	}

	if( gUnitLogLevel > 2 )
	{
		CvWString szString;
		getUnitAIString(szString, AI_getUnitAIType());
		logBBAI("    %S's %S at (%d,%d) finds no exploration target", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE());
	}

	if (!isHuman())
	{
		if (AI_pillage())
		{
			return;
		}
	}

	if (!isHuman())
	{
		if (AI_travelToUpgradeCity())
		{
			return;
		}
	}

	if (AI_refreshExploreRange(3))
	{
		return;
	}

	if( gUnitLogLevel > 2 )
	{
		CvWString szString;
		getUnitAIString(szString, AI_getUnitAIType());
		logBBAI("    %S's %S at (%d,%d) finds nothing at all to explore", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getName(0).GetCString(), getX_INLINE(), getY_INLINE());
	}

	if (!isHuman() && (AI_getUnitAIType() == UNITAI_EXPLORE))
	{
		if (GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(area(), UNITAI_EXPLORE) > GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(area()))
		{
			if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
			{
				scrap();
				return;
			}
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      12/03/08                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( !isHuman() && plot()->isCoastalLand() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_PICKUP) > 0 )
	{
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_travelToUpgradeCity())
	{
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_missionaryMove()
{
	PROFILE_FUNC();

	if (AI_spreadReligion())
	{
		return;
	}

	if (AI_spreadCorporation())
	{
		return;
	}
/************************************************************************************************/
/* RevolutionDCM  Inquisitions                             12/31/09             Afforess        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	if (AI_doInquisition())
	{
		return;
	}
/************************************************************************************************/
/* RevolutionDCM	                         END                                                */
/************************************************************************************************/
	if (!isHuman() || (isAutomated() && GET_TEAM(getTeam()).getAtWarCount(true) == 0))
	{
		if (!isHuman() || (getGameTurnCreated() < GC.getGame().getGameTurn()))
		{
			if (AI_spreadReligionAirlift())
			{
				return;
			}
			if (AI_spreadCorporationAirlift())
			{
				return;
			}
		}
		
		if (!isHuman())
		{
			if (AI_load(UNITAI_MISSIONARY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_SAFE_TERRITORY))
			{
				return;
			}

			if (AI_load(UNITAI_MISSIONARY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
			{
				return;
			}
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_prophetMove()
{
	PROFILE_FUNC();

	if (AI_construct(1))
	{
		return;
	}

	if (AI_discover(true, true))
	{
		return;
	}

	if (AI_construct(3))
	{
		return;
	}
	
	int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
	int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));

	if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
	{
        if (AI_goldenAge())
        {
            return;
        }

        if (iDiscoverValue > iGoldenAgeValue)
        {
            if (AI_discover())
            {
                return;
            }
            if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
            {
                if (AI_join())
                {
                    return;
                }
            }
        }
	}
	else
	{
		if (AI_discover())
		{
			return;
		}

		if (AI_join())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	//if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
	if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		  (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
	{
		if (AI_discover())
		{
			return;
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_artistMove()
{
	PROFILE_FUNC();
	
	if (AI_artistCultureVictoryMove())
	{
	    return;
	}

	if (AI_construct())
	{
		return;
	}

	if (AI_discover(true, true))
	{
		return;
	}

	if (AI_greatWork())
	{
		return;
	}

	int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
	int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));

	if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
	{
        if (AI_goldenAge())
        {
            return;
        }

        if (iDiscoverValue > iGoldenAgeValue)
        {
            if (AI_discover())
            {
                return;
            }
            if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
            {
                if (AI_join())
                {
                    return;
                }
            }
        }
	}
	else
	{
		if (AI_discover())
		{
			return;
		}

		if (AI_join())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	//if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
	if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		  (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
	{
		if (AI_discover())
		{
			return;
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_scientistMove()
{
	PROFILE_FUNC();

	if (AI_discover(true, true))
	{
		return;
	}

	if (AI_construct(MAX_INT, 1))
	{
		return;
	}
	if (GET_PLAYER(getOwnerINLINE()).getCurrentEra() < 3)
	{
		if (AI_join(2))
		{
			return;
		}		
	}
	
	if (GET_PLAYER(getOwnerINLINE()).getCurrentEra() <= (GC.getNumEraInfos() / 2))
	{
		if (AI_construct())
		{
			return;
		}
	}

	int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
	int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));

	if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
	{
        if (AI_goldenAge())
        {
            return;
        }

        if (iDiscoverValue > iGoldenAgeValue)
        {
            if (AI_discover())
            {
                return;
            }
            if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
            {
                if (AI_join())
                {
                    return;
                }
            }
        }
	}
	else
	{
		if (AI_discover())
		{
			return;
		}

		if (AI_join())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	//if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
	if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		  (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
	{
		if (AI_discover())
		{
			return;
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_generalMove()
{
	PROFILE_FUNC();

	std::vector<UnitAITypes> aeUnitAITypes;
	int iDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2);
	
	bool bOffenseWar = (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
	bool bCanDefend = getGroup()->canDefend();

	//	Generals always try to get an escort before moving away from a city
	if ( !bCanDefend && m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() && !isCargo() )
	{
		//	For now advertise the work as being here since we'll be holding position
		//	while we wait for a defender.  It would be more optimal to 'meet' the defender
		//	on the way or at the target plot, but this might leave us exposed on the way so
		//	the calculations involved are somewhat harder and not attempted for now
		if( gUnitLogLevel >= 3 )
		{
			logBBAI("    Great General for player %d (%S) at (%d,%d) requesting an escort",
					getOwner(),
					GET_PLAYER(getOwner()).getCivilizationDescription(0),
					plot()->getX_INLINE(),
					plot()->getY_INLINE());
		}

		GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(LOW_PRIORITY_ESCORT_PRIORITY, (unitCapabilities)(DEFENSIVE_UNITCAPABILITIES | OFFENSIVE_UNITCAPABILITIES), plot()->getX_INLINE(), plot()->getY_INLINE(), this);

		m_contractsLastEstablishedTurn = GC.getGameINLINE().getGameTurn();
		m_contractualState = CONTRACTUAL_STATE_AWAITING_ANSWER;

		//	Make sure we stay in charge when our escort joins us
		AI_setLeaderPriority(LEADER_PRIORITY_MAX);
	}
/************************************************************************************************/
/* Afforess	                  Start		 06/5/10                       Coded By: KillMePlease   */
/*                                                                                              */
/* Great Commanders                                                                             */
/************************************************************************************************/
	//bool bDefensiveWar = (area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE);
	if (isCommander())
	{
		//	Koshling - we cannot both advertise ourselves as available AND request help in the same turn, so alternate between
		//	for now (if we try to and happen to be last in the unit processing sequence out eventual request
		//	can wind up not being processed by any units so always forces a city build request - when built that unit may also
		//	not join us for exactly the same reason)
		bool bLookForWork = (GC.getGameINLINE().getGameTurn() % 2 == 0);

		//	If we're reasonably trained up then break off for any request, otherwise
		//	keep trying to train up unless there are high priority requests
		if ( bLookForWork )
		{
			if ( bCanDefend && processContracts((getLevel() < 4 ? LOW_PRIORITY_ESCORT_PRIORITY+1 : 0)) )
			{
				if( gUnitLogLevel >= 3 && m_contractualState == CONTRACTUAL_STATE_FOUND_WORK )
				{
					logBBAI("    Great General for player %d (%S) at (%d,%d) found contractual work",
							getOwner(),
							GET_PLAYER(getOwner()).getCivilizationDescription(0),
							plot()->getX_INLINE(),
							plot()->getY_INLINE());
				}
				return;
			}

			if( gUnitLogLevel >= 3 )
			{
				logBBAI("    Great General for player %d (%S) at (%d,%d) found no urgent contractual work",
						getOwner(),
						GET_PLAYER(getOwner()).getCivilizationDescription(0),
						plot()->getX_INLINE(),
						plot()->getY_INLINE());
			}
		}

		if (bOffenseWar && getLevel() >= 4)
		{
			//try to join SoD (?)
			if (AI_group(UNITAI_ATTACK, -1, 1, 6, false, false, true, bCanDefend ? MAX_INT : 1, true, false, false)) 
			{
				return;
			}
			if (AI_group(UNITAI_ATTACK, -1, 1, 4, false, false, true, bCanDefend ? MAX_INT : 1, true, false, false)) 
			{
				return;
			}
			if (AI_group(UNITAI_ATTACK_CITY, -1, 1, 4, false, false, true, bCanDefend ? MAX_INT : 1, true, false, false)) 
			{
				return;
			}
			if (AI_group(UNITAI_COLLATERAL, -1, 1, 4, false, false, true, bCanDefend ? MAX_INT : 1, true, false, false)) 
			{
				return;
			}
			if (AI_group(UNITAI_COUNTER, -1, 1, 3, false, false, true, bCanDefend ? MAX_INT : 1, true, false, false)) 
			{
				return;
			}
			//Koshling - remove attempts to join small stacks now that we have generals requestign escorts and
			//repsonding to explicit requests themselves
			//try to join attacking stack
			//if (AI_group(UNITAI_ATTACK, -1, 1, -1, false, false, false, bCanDefend ? MAX_INT : 1)) 
			//{
			//	return;
			//}

			//if (AI_group(UNITAI_ATTACK_CITY, -1, 1, -1, false)) 
			//{
			//	return;
			//}
			//try airlift
			if (AI_offensiveAirlift()) 
			{
				return;
			}
			//try load on transport
			if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, 2, -1, 0, ((bCanDefend ? MOVE_SAFE_TERRITORY : MOVE_OUR_TERRITORY) | MOVE_WITH_CAUTION))) 
			{
				return;
			}
		}

		//	Try to hook up with a hunter and exp up - we always seek to have a stack of at least one
		//	general escort unit, the hunter, and the general
		bool bHasHunter = getGroup()->hasUnitOfAI(UNITAI_HUNTER);

		if ( bHasHunter )
		{
			if ( getGroup()->getNumUnits() > 2 )
			{
				if( gUnitLogLevel > 2 )
				{
					logBBAI("    %S's great commander (%d) at (%d,%d) [stack size %d, exp %d] executes hunter AI to exp up", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getID(), getX_INLINE(), getY_INLINE(), getGroup()->getNumUnits(), getExperience());
				}
				//	Already have hunter + another escort =- execute modified hunter AI
				AI_SearchAndDestroyMove(true);
				return;
			}
			else if ( !bLookForWork && !isCargo() )
			{
				//	Get another escort unit
				GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(HIGH_PRIORITY_ESCORT_PRIORITY,
																			   (unitCapabilities)(DEFENSIVE_UNITCAPABILITIES | OFFENSIVE_UNITCAPABILITIES),
																			   getX_INLINE(),
																			   getY_INLINE(),
																			   this);

				if( gUnitLogLevel > 2 )
				{
					logBBAI("    %S's great commander (%d) at (%d,%d) requests escort at priority %d", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getID(), getX_INLINE(), getY_INLINE(), HIGH_PRIORITY_ESCORT_PRIORITY);
				}
			}
		}
		else if ( !bLookForWork && !isCargo() )
		{
			GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(HIGHEST_PRIORITY_ESCORT_PRIORITY,
																		   NO_UNITCAPABILITIES,
																		   getX_INLINE(),
																		   getY_INLINE(),
																		   this,
																		   UNITAI_HUNTER);

			if( gUnitLogLevel > 2 )
			{
				logBBAI("    %S's great commander (%d) at (%d,%d) [stack size %d] requests hunter at priority %d", GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), getID(), getX_INLINE(), getY_INLINE(), getGroup()->getNumUnits(), HIGH_PRIORITY_ESCORT_PRIORITY);
			}
		}

		if (AI_retreatToCity())
		{
			return;
		}
		if (AI_safety())
		{
			return;
		} 
		getGroup()->pushMission(MISSION_SKIP);
		return;

	}
	else
	{
		if (AI_command())
		{
			//Does not use it's turn
			AI_generalMove();
			return;
		}
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
/************************************************************************************************/
/* BETTER_BTS_AI_MOD & RevDCM                     09/03/10                        jdog5000      */
/*                                                                                phungus420    */
/* Great People AI, Unit AI                                                                     */
/************************************************************************************************/
	if (AI_leadLegend())
	{
		return;
	}

	if (iDanger > 0)
	{
		aeUnitAITypes.clear();
		aeUnitAITypes.push_back(UNITAI_ATTACK);
		aeUnitAITypes.push_back(UNITAI_COUNTER);
		if (AI_lead(aeUnitAITypes))
		{
			return;
		}
	}
/************************************************************************************************/
/* Afforess	                  Start		 10/31/10                                               */
/*                                                                                              */
/* Military City AI                                                                             */
/************************************************************************************************/
	if (AI_joinMilitaryCity())
	{
		return;
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/

	if (AI_construct(1))
	{
		return;
	}
	if (AI_join(1))
	{
		return;
	}

	if (bOffenseWar && (AI_getBirthmark() % 2 == 0))
	{
		aeUnitAITypes.clear();
		aeUnitAITypes.push_back(UNITAI_ATTACK_CITY);
		if (AI_lead(aeUnitAITypes))
		{
			return;
		}

		aeUnitAITypes.clear();
		aeUnitAITypes.push_back(UNITAI_ATTACK);
		if (AI_lead(aeUnitAITypes))
		{
			return;
		}
	}

	if (AI_join(2))
	{
		return;
	}

	if (AI_construct(2))
	{
		return;
	}
	if (AI_join(4))
	{
		return;
	}
	
	if (GC.getGameINLINE().getSorenRandNum(3, "AI General Construct") == 0)
	{
		if (AI_construct())
		{
			return;
		}
	}

	if (AI_join())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_merchantMove()
{
	PROFILE_FUNC();

	if (AI_construct())
	{
		return;
	}

	if (AI_discover(true, true))
	{
		return;
	}
/************************************************************************************************/
/* Afforess	                  Start		 04/23/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	if (AI_caravan(false))
	{
		return;
	}
	if (AI_caravan(true))
	{
		return;
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
	int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));

	if (AI_trade(iGoldenAgeValue * 2))
	{
	    return;
	}

	if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
	{
        if (AI_goldenAge())
        {
            return;
        }

        if (AI_trade(iGoldenAgeValue))
        {
            return;
        }

        if (iDiscoverValue > iGoldenAgeValue)
        {
            if (AI_discover())
            {
                return;
            }
            if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
            {
                if (AI_join())
                {
                    return;
                }
            }
        }
	}
	else
	{
		if (AI_discover())
		{
			return;
		}

		if (AI_join())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	//if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
	if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		  (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
	{
		if (AI_discover())
		{
			return;
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

void CvUnitAI::AI_subduedAnimalMove()
{
	PROFILE_FUNC();

	if ( getDamage() > 0 )
	{
		OutputDebugString(CvString::format("%S (%d) damaged (%d) at (%d,%d)...\n",getDescription().c_str(),m_iID,getDamage(),m_iX,m_iY).c_str());
		//	Don't bother healing subdued animals in our own territory at least until after we test if they can construct
		if ( plot()->getOwnerINLINE() != getOwnerINLINE() )
		{
			//	If they can get to our territory prefer that to healing
			if ( AI_moveToOurTerritory(1) )
			{
				return;
			}

			//	Try to move to a nearby hunter unit if one is available to group with it
			if (AI_groupMergeRange(UNITAI_HUNTER, 1, false, true, true))
			{
				return;
			}

			//	If there is an adjacent enemy seek safety before we heal
			if ( exposedToDanger(plot(), 80) )
			{
				OutputDebugString("    ...plot is dangerous - seeking safety\n");

				if ( AI_safety() )
				{
					return;
				}
			}

			//	Failing that are there other animals nearby - safety in numbers
			if (AI_groupMergeRange(UNITAI_SUBDUED_ANIMAL, 1, false, true, true))
			{
				return;
			}

			if ( AI_heal() )
			{
				OutputDebugString("    ...healing\n");
				return;
			}

			if ( AI_safety() )
			{
				return;
			}
		}
		else if ( getGroup()->getNumUnits() > 1 )
		{
			//	Separate groups of subdued animals once they reach owned territory
			getGroup()->AI_separate();

			//	Will have changed group so the previous one no longer exists to deal with
			return;
		}
	}

	if (AI_construct(MAX_INT, MAX_INT, 0, false, true))
	{
		OutputDebugString(CvString::format("%S (%d) chooses to head off to construct\n",getDescription().c_str(),m_iID).c_str());
		return;
	}

	if (AI_outcomeMission())
	{
		OutputDebugString(CvString::format("%S (%d) chooses to head off to do an outcome mission\n",getDescription().c_str(),m_iID).c_str());
		return;
	}

	AI_upgrade();
	if ( isDelayedDeath() )
	{
		//	Upgrade of original unit was successful
		return;
	}

	if (AI_scrapSubdued())
	{
		OutputDebugString(CvString::format("%S (%d) chooses to disband\n",getDescription().c_str(),m_iID).c_str());
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

void CvUnitAI::AI_engineerMove()
{
	PROFILE_FUNC();

	if (AI_construct())
	{
		OutputDebugString(CvString::format("%S (%d) chooses to head off to construct\n",getDescription().c_str(),m_iID).c_str());
		return;
	}

	if (AI_switchHurry())
	{
		return;
	}

	if (AI_hurry())
	{
		return;
	}

	if (AI_discover(true, true))
	{
		return;
	}

	int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
	int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));

	if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
	{
        if (AI_goldenAge())
        {
            return;
        }

        if (iDiscoverValue > iGoldenAgeValue)
        {
            if (AI_discover())
            {
                return;
            }
            if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
            {
                if (AI_join())
                {
                    return;
                }
            }
        }
	}
	else
	{
		if (AI_discover())
		{
			return;
		}

		if (AI_join())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	//if ((GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) ||
	if ((GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2)) ||
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		  (getGameTurnCreated() < (GC.getGameINLINE().getGameTurn() - 25)))
	{
		if (AI_discover())
		{
			return;
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
	if( getGroup()->isStranded() )
	{
		if (AI_load(UNITAI_ASSAULT_SEA, MISSIONAI_LOAD_ASSAULT, NO_UNITAI, -1, -1, -1, -1, MOVE_NO_ENEMY_TERRITORY, 1))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/25/10                                jdog5000      */
/*                                                                                              */
/* Espionage AI                                                                                 */
/************************************************************************************************/
void CvUnitAI::AI_spyMove()
{
	PROFILE_FUNC();

	CvTeamAI& kTeam = GET_TEAM(getTeam());
	int iEspionageChance = 0;
	if (plot()->isOwned() && (plot()->getTeam() != getTeam()))
	{
		switch (GET_PLAYER(getOwnerINLINE()).AI_getAttitude(plot()->getOwnerINLINE()))
		{
		case ATTITUDE_FURIOUS:
			iEspionageChance = 100;
			break;

		case ATTITUDE_ANNOYED:
			iEspionageChance = 50;
			break;

		case ATTITUDE_CAUTIOUS:
			iEspionageChance = (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 30 : 10);
			break;

		case ATTITUDE_PLEASED:
			iEspionageChance = (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 20 : 0);
			break;

		case ATTITUDE_FRIENDLY:
			iEspionageChance = 0;
			break;

		default:
			FAssert(false);
			break;
		}
		
		WarPlanTypes eWarPlan = kTeam.AI_getWarPlan(plot()->getTeam());
		if (eWarPlan != NO_WARPLAN)
		{
			if (eWarPlan == WARPLAN_LIMITED)
			{
				iEspionageChance += 50;
			}
			else
			{
				iEspionageChance += 20;
			}
		}
		
		if (plot()->isCity() && plot()->getTeam() != getTeam())
		{
			bool bTargetCity = false;

			// would we have more power if enemy defenses were down?
			int iOurPower = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),1,false,true);
			int iEnemyPower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,false,false);

			if( 5*iOurPower > 6*iEnemyPower && eWarPlan != NO_WARPLAN )
			{
				bTargetCity = true;

				if( AI_revoltCitySpy() )
				{
					return;
				}

				if (GC.getGame().getSorenRandNum(5, "AI Spy Skip Turn") > 0)
				{
					getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
					return;
				}

				if ( AI_cityOffenseSpy(5, plot()->getPlotCity()) )
				{
					return;
				}
			}
			
			if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(plot(), MISSIONAI_ASSAULT, getGroup()) > 0 )
			{
				bTargetCity = true;

				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
				return;
			}
			
			if( !bTargetCity )
			{
				// normal city handling
				if (getFortifyTurns() >= GC.getDefineINT("MAX_FORTIFY_TURNS"))
				{
					if (AI_espionageSpy())
					{
						return;
					}
				}
				else if (GC.getGame().getSorenRandNum(100, "AI Spy Skip Turn") > 5)
				{
					// don't get stuck forever
					getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
					return;
				}
			}
		}
		else if (GC.getGameINLINE().getSorenRandNum(100, "AI Spy Espionage") < iEspionageChance)
		{
			// This applies only when not in an enemy city, so for destroying improvements
			if (AI_espionageSpy())
			{
				return;
			}
		}
	}
	
	if (plot()->getTeam() == getTeam())
	{
		if (kTeam.getAnyWarPlanCount(true) == 0 || GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_SPACE4) || GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3))
		{
			if( GC.getGame().getSorenRandNum(10, "AI Spy defense") > 0)
			{
				if (AI_guardSpy(0))
				{
					return;			
				}
			}
		}
		
		if (GC.getGame().getSorenRandNum(100, "AI Spy pillage improvement") < 25)
		{
			if (AI_bonusOffenseSpy(5))
			{
				return;
			}
		}
		else
		{
			if (AI_cityOffenseSpy(10))
			{
				return;
			}
		}
	}
	
	if (iEspionageChance > 0 && (plot()->isCity() || (plot()->getNonObsoleteBonusType(getTeam()) != NO_BONUS)))
	{
		if (GC.getGame().getSorenRandNum(7, "AI Spy Skip Turn") > 0)
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
			return;
		}
	}

	if( area()->getNumCities() > area()->getCitiesPerPlayer(getOwnerINLINE()) )
	{
		if (GC.getGame().getSorenRandNum(4, "AI Spy Choose Movement") > 0)
		{
			if (AI_reconSpy(3))
			{
				return;
			}
		}
		else
		{
			if (AI_cityOffenseSpy(10))
			{
				return;
			}
		}
	}
	
	if (AI_load(UNITAI_SPY_SEA, MISSIONAI_LOAD_SPECIAL, NO_UNITAI, -1, -1, -1, 0, MOVE_NO_ENEMY_TERRITORY))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                   */
/************************************************************************************************/

void CvUnitAI::AI_ICBMMove()
{
	PROFILE_FUNC();

//	CvCity* pCity = plot()->getPlotCity();

//	if (pCity != NULL)
//	{
//		if (pCity->AI_isDanger())
//		{
//			if (!(pCity->AI_isDefended()))
//			{
//				if (AI_airCarrier())
//				{
//					return;
//				}
//			}
//		}
//	}
	
	if (airRange() > 0)
	{
		if (AI_nukeRange(airRange()))
		{
			return;
		}
	}
	else if (AI_nuke())
	{
		return;
	}

	if (isCargo())
	{
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}
	
	if (airRange() > 0)
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/25/10                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
		if (plot()->isCity(true))
		{
			int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
			int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

			if (4*iEnemyOffense > iOurDefense || iOurDefense == 0)
			{
				// Too risky, pull back
				if (AI_airOffensiveCity())
				{
					return;
				}
			}
		}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

		if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA, 2, true))
		{
			return;
		}
		
		if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA, 1, false))
		{
			return;
		}
		
		if (AI_getBirthmark() % 3 == 0)
		{
			if (AI_missileLoad(UNITAI_ATTACK_SEA, 0, false))
			{
				return;
			}
		}
		
		if (AI_airOffensiveCity())
		{
			return;
		}
	}

	getGroup()->pushMission(MISSION_SKIP);
}


void CvUnitAI::AI_workerSeaMove()
{
	PROFILE_FUNC();

	CvCity* pCity;
	
	if (!(getGroup()->canDefend()))
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
		//if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
		if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		{
			if (AI_retreatToCity())
			{
				return;
			}
		}
	}

	if (AI_improveBonus(20))
	{
		return;
	}

	if (AI_improveBonus(10))
	{
		return;
	}

	if (AI_improveBonus())
	{
		return;
	}

	
	if (AI_improveLocalPlot(2, NULL))
	{
		return;		
	}

	if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_WORKER_SEA))
	{
		pCity = plot()->getPlotCity();

		if (pCity != NULL)
		{
			if (pCity->getOwnerINLINE() == getOwnerINLINE())
			{
				if (pCity->AI_neededSeaWorkers() == 0)
				{
					if (GC.getGameINLINE().getElapsedGameTurns() > 10)
					{
						if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
						{
							scrap();
							return;
						}
					}
				}
				else
				{
					//Probably icelocked since it can't perform actions.
					scrap();
					return;
				}	
			}
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_barbAttackSeaMove()
{
	PROFILE_FUNC();

	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						9/25/08				jdog5000	*/
	/* 																			*/
	/* 	Barbarian AI															*/
	/********************************************************************************/
	/* original BTS code
	if (GC.getGameINLINE().getSorenRandNum(2, "AI Barb") == 0)
	{
		if (AI_pillageRange(1))
		{
			return;
		}
	}

	if (AI_anyAttack(2, 25))
	{
		return;
	}

	if (AI_pillageRange(4))
	{
		return;
	}

	if (AI_heal())
	{
		return;
	}
	*/
	// Less suicide, always chase good targets
	if( AI_anyAttack(2,51) )
	{
		return;
	}

	if (AI_pillageRange(1))
	{
		return;
	}

	if( AI_anyAttack(1,34) )
	{
		return;
	}

	// We're easy to take out if wounded
	if (AI_heal())
	{
		return;
	}

	if (AI_pillageRange(3))
	{
		return;
	}

	// Barb ships will often hang out for a little while blockading before moving on
	if( (GC.getGame().getGameTurn() + getID())%12 > 5 )
	{
		if( AI_pirateBlockade())
		{
			return;
		}
	}

	if( GC.getGameINLINE().getSorenRandNum(3, "AI Check trapped") == 0 )
	{
		// If trapped in small hole in ice or around tiny island, disband to allow other units to be generated
		bool bScrap = true;
		int iMaxRange = baseMoves() + 2;
		for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
		{
			for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
			{
				if( bScrap )
				{
					CvPlot* pLoopPlot = plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), iDX, iDY);
					
					if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
					{
						int iPathTurns;
						if (generatePath(pLoopPlot, 0, true, &iPathTurns))
						{
							if( iPathTurns > 1 )
							{
								bScrap = false;
							}
						}
					}
				}
			}
		}

		if( bScrap )
		{
			scrap();
		}
	}
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						END								*/
	/********************************************************************************/

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/23/10                    Afforess & jdog5000       */
/*                                                                                              */
/* Pirate AI                                                                                    */
/************************************************************************************************/
void CvUnitAI::AI_pirateSeaMove()
{
	PROFILE_FUNC();
	
/************************************************************************************************/
/* Afforess/RevDCM                      02/23/10                                                */
/*                                                                                              */
/* Advanced Automations                                                                         */
/************************************************************************************************/
	//returns 0 if not set
	int iMinimumOdds = GET_PLAYER(getOwnerINLINE()).getModderOption(MODDEROPTION_AUTO_PIRATE_MIN_COMBAT_ODDS);
/************************************************************************************************/
/* Afforess/RevDCM                       END                                                    */
/************************************************************************************************/

	CvArea* pWaterArea;

	// heal in defended, unthreatened forts and cities
	if (plot()->isCity(true) && (GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),0,true,false) > 0) && !(GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot(), 2, false)) )
	{
		if (AI_heal())
		{
			return;
		}
	}

	if (plot()->isOwned() && (plot()->getTeam() == getTeam()))
	{
		if (AI_anyAttack(2, 40))
		{
			return;			
		}
		
		//if (AI_protect(30))
		if (AI_protect(40, 3))
		{
			return;
		}
		

		if (((AI_getBirthmark() / 8) % 2) == 0)
		{
			// Previously code actually blocked grouping
			if (AI_group(UNITAI_PIRATE_SEA, -1, 1, -1, true, false, false, 8))
			{
				return;
			}
		}
	}
	else
	{
		if (AI_anyAttack(2, 51))
		{
			return;
		}
	}

	
	if (GC.getGame().getSorenRandNum(10, "AI Pirate Explore") == 0)
	{
		pWaterArea = plot()->waterArea();

		if (pWaterArea != NULL)
		{
			if (pWaterArea->getNumUnrevealedTiles(getTeam()) > 0)
			{
				if (GET_PLAYER(getOwnerINLINE()).AI_areaMissionAIs(pWaterArea, MISSIONAI_EXPLORE, getGroup()) < (GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(pWaterArea)))
				{
					if (AI_exploreRange(2))
					{
						return;
					}
				}
			}
		}
	}

	if (GC.getGame().getSorenRandNum(11, "AI Pirate Pillage") == 0)
	{
		if (AI_pillageRange(1))
		{
			return;
		}
	}
	
	//Includes heal and retreat to sea routines.
	if (AI_pirateBlockade())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


void CvUnitAI::AI_attackSeaMove()
{
	PROFILE_FUNC();
	MEMORY_TRACK();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						06/14/09	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		PROFILE("CvUnitAI::AI_attackSeaMove.City");

		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4  || iOurDefense == 0) //prioritize getting outta there
		{
			if (AI_anyAttack(2, 50))
			{
				return;
			}

			if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, false, true, 2))
			{
				return;
			}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
			//if (AI_protect(35))
			if (AI_protect(35, 3))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (AI_heal(30, 1))
	{
		return;
	}
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                            Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - sea bombard AI formally DCM 1.7 AI_RbombardCity()
	// Dale - RB: Field Bombard START
	//if (AI_RbombardCity())
	//{
	//	return;
	//}
	if (AI_RbombardNaval())
	{
		return;
	}
	// Dale - RB: Field Bombard END

	// Dale - ARB: Archer Bombard START
	if (AI_Abombard())
	{
		return;
	}
	// Dale - ARB: Archer Bombard END
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                Glider1    */
/************************************************************************************************/

	{
		PROFILE("CvUnitAI::AI_attackSeaMove.BasicAttacks");

		if (AI_anyAttack(1, 35))
		{
			return;
		}
		
		if (AI_anyAttack(2, 40))
		{
			return;
		}
		
		if (AI_goody(2))
		{
			return;
		}
		
		if (AI_seaBombardRange(6))
		{
			return;
		}
		
		if (AI_heal(50, 3))
		{
			return;
		}

		if (AI_heal())
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/10/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	// BBAI TODO: Turn this into a function, have docked escort ships do it to

	//Fuyu: search for more attackers, and when enough are found, always try to break through
	CvCity* pCity = plot()->getPlotCity();

	if( pCity != NULL )
	{
		if( pCity->isBlockaded() )
		{
			PROFILE("CvUnitAI::AI_attackSeaMove.Blockaded");

			int iBlockadeRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE");
			// City under blockade
			// Attacker has low odds since anyAttack checks above passed, try to break if sufficient numbers

			int iAttackers = plot()->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
			int iBlockaders = GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), (iBlockadeRange + 1));
			//bool bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);

			if (true)
			{
				int iMaxRange = iBlockadeRange - 1;
				if( gUnitLogLevel > 2 ) logBBAI("      Not enough attack fleet found in %S, searching for more in a %d-tile radius", pCity->getName().GetCString(), iMaxRange);

				for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
				{
					for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
					{
						CvPlot* pLoopPlot = plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), iDX, iDY);
							
						if (pLoopPlot != NULL && pLoopPlot->isWater())
						{
							if (pLoopPlot->getBlockadedCount(getTeam()) > 0)
							{
								iAttackers += pLoopPlot->plotCount(PUF_isUnitAIType, UNITAI_ATTACK_SEA, -1, NO_PLAYER, getTeam(), PUF_isGroupHead, -1, -1);
							}
						}
					}
				}
			}
			//bBreakBlockade = (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders);

			//if (bBreakBlockade)
			if (iAttackers > (iBlockaders + 2) || iAttackers >= 2*iBlockaders)
			{
				if( gUnitLogLevel > 2 ) logBBAI("      Found %d attackers and %d blockaders, proceeding to break blockade", iAttackers, iBlockaders);
				if(true) /* (iAttackers > GC.getGameINLINE().getSorenRandNum(2*iBlockaders + 1, "AI - Break blockade")) */
				{
					// BBAI TODO: Make odds scale by # of blockaders vs number of attackers
					if (baseMoves() >= iBlockadeRange)
					{
						if (AI_anyAttack(1, 15))
						{
							return;
						}
					}
					else
					{
						//Fuyu: Even slow ships should attack
						//Assuming that every ship can reach a blockade with 2 moves
						if (AI_anyAttack(2, 15))
						{
							return;
						}
					}
					
					//If no mission was pushed yet and we have a lot of ships, try again with even lower odds
					if(iAttackers > 2*iBlockaders)
					{
						if (AI_anyAttack(1, 10))
						{
							return;
						}
					}
				}
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	
	if (AI_group(UNITAI_CARRIER_SEA, /*iMaxGroup*/ 4, 1, -1, true, false, false, /*iMaxPath*/ 5))
	{
		return;
	}
	
	if (AI_group(UNITAI_ATTACK_SEA, /*iMaxGroup*/ 1, -1, -1, true, false, false, /*iMaxPath*/ 3))
	{
		return;
	}
	
	if (!plot()->isOwned() || !isEnemy(plot()->getTeam()))
	{
		PROFILE("CvUnitAI::AI_attackSeaMove.Neutral");

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/11/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
		if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34))
		{
			return;
		}
		
		if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51))
		{
			return;
		}

		if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, -1, false, false, false))
		{
			return;
		}
	}
	
	if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false))
	{
		return;
	}
*/
		if (AI_shadow(UNITAI_ASSAULT_SEA, 4, 34, true, false, 4))
		{
			return;
		}
		
		if (AI_shadow(UNITAI_CARRIER_SEA, 4, 51, true, false, 5))
		{
			return;
		}

		// Group with large flotillas first
		if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, 3, false, false, false, 3, false, true, false))
		{
			return;
		}

		if (AI_group(UNITAI_ASSAULT_SEA, -1, 2, -1, false, false, false, 5, false, true, false))
		{
			return;
		}
	}
	
	if (AI_group(UNITAI_CARRIER_SEA, -1, 1, -1, false, false, false, 10))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	
	if (plot()->isOwned() && (isEnemy(plot()->getTeam())))
	{
		if (AI_blockade())
		{
			return;
		}
	}
	if (AI_pillageRange(4))
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	//if (AI_protect(35))
	if (AI_protect(35, 3))
	{
		return;
	}

	if (AI_protect(35, 8))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		return;
	}

	if (AI_travelToUpgradeCity())
	{
		return;
	}

	if (AI_seaAreaAttack())
	{
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_reserveSeaMove()
{
	PROFILE_FUNC();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						06/14/09	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4  || iOurDefense == 0)  //prioritize getting outta there
		{
			if (AI_anyAttack(2, 60))
			{
				return;
			}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
			//if (AI_protect(40))
			if (AI_protect(40, 3))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			{
				return;
			}

			if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 4))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (AI_guardBonus(30))
	{
		return;
	}

	if (AI_heal(30, 1))
	{
		return;
	}

	if (AI_anyAttack(1, 55))
	{
		return;
	}
	
	if (AI_seaBombardRange(6))
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	//if (AI_protect(40))
	if (AI_protect(40, 5))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		return;
	}
	
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/03/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
	if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true))
	{
		return;
	}

	if (AI_group(UNITAI_RESERVE_SEA, 1))
	{
		return;
	}
	
	if (bombardRate() > 0)
	{
		if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true))
		{
			return;
		}
	}
*/
	// Shadow any nearby settler sea transport out at sea
	if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 5))
	{
		return;
	}
	
	if (AI_group(UNITAI_RESERVE_SEA, 1, -1, -1, false, false, false, 8))
	{
		return;
	}
	
	if (getGroup()->hasBombardCapability())
	{
		if (AI_shadow(UNITAI_ASSAULT_SEA, 2, 30, true, false, 8))
		{
			return;
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/	

	if (AI_heal(50, 3))
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	if (AI_protect(40))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_anyAttack(3, 45))
	{
		return;
	}

	if (AI_heal())
	{
		return;
	}

	if (!isNeverInvisible())
	{
		if (AI_anyAttack(5, 35))
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/03/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                      */
/************************************************************************************************/
	// Shadow settler transport with cargo 
	if (AI_shadow(UNITAI_SETTLER_SEA, 1, -1, true, false, 10))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_travelToUpgradeCity())
	{
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_escortSeaMove()
{
	PROFILE_FUNC();

//	// if we have cargo, possibly convert to UNITAI_ASSAULT_SEA (this will most often happen with galleons)
//	// note, this should not happen when we are not the group head, so escort galleons are fine joining a group, just not as head
//	if (hasCargo() && (getUnitAICargo(UNITAI_ATTACK_CITY) > 0 || getUnitAICargo(UNITAI_ATTACK) > 0))
//	{
//		// non-zero AI_unitValue means that UNITAI_ASSAULT_SEA is valid for this unit (that is the check used everywhere)
//		if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, NULL) > 0)
//		{
//			// save old group, so we can merge it back in
//			CvSelectionGroup* pOldGroup = getGroup();
//
//			// this will remove this unit from the current group
//			AI_setUnitAIType(UNITAI_ASSAULT_SEA);
//
//			// merge back the rest of the group into the new group
//			CvSelectionGroup* pNewGroup = getGroup();
//			if (pOldGroup != pNewGroup)
//			{
//				pOldGroup->mergeIntoGroup(pNewGroup);
//			}
//
//			// perform assault sea action
//			AI_assaultSeaMove();
//			return;
//		}
//	}

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						06/14/09	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true)) //prioritize getting outta there
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4  || iOurDefense == 0)
		{
			if (AI_anyAttack(1, 60))
			{
				return;
			}

			if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 1, -1, /*bIgnoreFaster*/ true, false, false, /*iMaxPath*/ 1))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (AI_heal(30, 1))
	{
		return;
	}

	if (AI_anyAttack(1, 55))
	{
		return;
	}
// Thomas SG - AC: Advanced Cargo START
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						9/14/08			jdog5000		*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	// Galleons can get stuck with this AI type since they don't upgrade to any escort unit
	// Galleon escorts are much less useful once Frigates or later are available
	if (!isHuman() && !isBarbarian())
	{
		{
			if( getCargo() > 0 && !(GC.getUnitInfo(getUnitType()).getNumSpecialCargos() > 0) )		
			{
				//Obsolete?
				int iValue = GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), AI_getUnitAIType(), area());
				int iBestValue = GET_PLAYER(getOwnerINLINE()).AI_bestAreaUnitAIValue(AI_getUnitAIType(), area());
				
				if (iValue < iBestValue)
				{	
					if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, area()) > 0)
					{
						AI_setUnitAIType(UNITAI_ASSAULT_SEA);
						return;
					}
	
					if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_SETTLER_SEA, area()) > 0)
					{
						AI_setUnitAIType(UNITAI_SETTLER_SEA);
						return;
					}
					scrap();
				}
			}
		}
	}		
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/
// Thomas SG - AC: Advanced Cargo END	
	if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 0, -1, /*bIgnoreFaster*/ true))
	{
		return;
	}
		
	if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 0, -1, /*bIgnoreFaster*/ true, false, false, /*iMaxPath*/ 3))
	{
		return;
	}

	if (AI_heal(50, 3))
	{
		return;
	}

	if (AI_pillageRange(2))
	{
		return;
	}
	
	if (AI_group(UNITAI_MISSILE_CARRIER_SEA, 1, 1, 1))
	{
		return;
	}

	if (AI_group(UNITAI_ASSAULT_SEA, 1, /*iMaxOwnUnitAI*/ 0, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
	{
		return;
	}
	
	if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
	{
		return;
	}
	
	if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ true))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/01/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                      */
/************************************************************************************************/
/* original bts code
	if (AI_group(UNITAI_ASSAULT_SEA, -1, 4, -1, true))
	{
		return;
	}
*/
	// Group only with large flotillas first
	if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 4, /*iMinUnitAI*/ 3, /*bIgnoreFaster*/ true))
	{
		return;
	}

	if (AI_shadow(UNITAI_SETTLER_SEA, 2, -1, false, true, 4))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/	

	if (AI_heal())
	{
		return;
	}

	if (AI_travelToUpgradeCity())
	{
		return;
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/18/10                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	// If nothing else useful to do, escort nearby large flotillas even if they're faster
	// Gives Caravel escorts something to do during the Galleon/pre-Frigate era
	if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 4, /*iMinUnitAI*/ 3, /*bIgnoreFaster*/ false, false, false, 4, false, true))
	{
		return;
	}

	if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ 2, /*iMinUnitAI*/ -1, /*bIgnoreFaster*/ false, false, false, 1, false, true))
	{
		return;
	}

	// Pull back to primary area if it's not too far so primary area cities know you exist
	// and don't build more, unnecessary escorts
	if (AI_retreatToCity(true,false,6))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_exploreSeaMove()
{
	PROFILE_FUNC();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true)) //prioritize getting outta there
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 )
		{
			if (!isHuman())
			{
				if (AI_anyAttack(1, 60))
				{
					return;
				}
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	CvArea* pWaterArea = plot()->waterArea();

	if (!isHuman())
	{
		if (AI_anyAttack(1, 60))
		{
			return;
		}
	}
	
	if (!isHuman() && !isBarbarian()) //XXX move some of this into a function? maybe useful elsewhere
	{
		//Obsolete?
		int iValue = GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), AI_getUnitAIType(), area());
		int iBestValue = GET_PLAYER(getOwnerINLINE()).AI_bestAreaUnitAIValue(AI_getUnitAIType(), area());
		
		if (iValue < iBestValue)
		{
			//Transform
			if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_WORKER_SEA, area()) > 0)
			{
				AI_setUnitAIType(UNITAI_WORKER_SEA);
				return;
			}
			
			if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_PIRATE_SEA, area()) > 0)
			{
				AI_setUnitAIType(UNITAI_PIRATE_SEA);
				return;
			}
			
			if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_MISSIONARY_SEA, area()) > 0)
			{
				AI_setUnitAIType(UNITAI_MISSIONARY_SEA);
				return;
			}
			
			if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_RESERVE_SEA, area()) > 0)
			{
				AI_setUnitAIType(UNITAI_RESERVE_SEA);
				return;
			}
			scrap();
		}		
	}

	if (getDamage() > 0)
	{
		if (plot()->getTotalTurnDamage(this) <= 0)
		{
			getGroup()->pushMission(MISSION_HEAL);
			return;
		}
	}

	if (!isHuman())
	{
		if (AI_pillageRange(1))
		{
			return;
		}
	}

	if (AI_exploreRange(4))
	{
		return;
	}

	if (!isHuman())
	{
		if (AI_pillageRange(4))
		{
			return;
		}
	}

	if (AI_explore())
	{
		return;
	}

	if (!isHuman())
	{
		if (AI_pillage())
		{
			return;
		}
	}
	
	if (!isHuman())
	{
		if (AI_travelToUpgradeCity())
		{
			return;
		}
	}

	if (!(isHuman()) && (AI_getUnitAIType() == UNITAI_EXPLORE_SEA))
	{
		pWaterArea = plot()->waterArea();

		if (pWaterArea != NULL)
		{
			if (GET_PLAYER(getOwnerINLINE()).AI_totalWaterAreaUnitAIs(pWaterArea, UNITAI_EXPLORE_SEA) > GET_PLAYER(getOwnerINLINE()).AI_neededExplorers(pWaterArea))
			{
				if (GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
				{
					scrap();
					return;
				}
			}
		}
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/18/10                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
void CvUnitAI::AI_assaultSeaMove()
{
	PROFILE_FUNC();

	FAssert(AI_getUnitAIType() == UNITAI_ASSAULT_SEA);

	bool bEmpty = !getGroup()->hasCargo();
	bool bFull = (getGroup()->AI_isFull() && (getGroup()->getCargo() > 0));
/************************************************************************************************/
/* Afforess	                  Start		 09/01/10                                               */
/*                                                                                              */
/*  After a Barb Transport is done, set it to attack AI                                         */
/************************************************************************************************/
	if (bEmpty && getOwnerINLINE() == BARBARIAN_PLAYER)
	{
		AI_setUnitAIType(UNITAI_ATTACK_SEA);
		AI_barbAttackSeaMove();
		return;
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/8 || iOurDefense == 0 )
		{
			if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
			{
				if( !bEmpty )
				{
					getGroup()->unloadAll();
				}

				if (AI_anyAttack(1, 65))
				{
					return;
				}

				// Retreat to primary area first
				if (AI_retreatToCity(true))
				{
					return;
				}

				if (AI_retreatToCity())
				{
					return;
				}

				if (AI_safety())
				{
					return;
				}
			}

			if( !bFull && !bEmpty )
			{
				getGroup()->unloadAll();
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}
		}
	}

	if (bEmpty)
	{
		if (AI_anyAttack(1, 65))
		{
			return;
		}
		if (AI_anyAttack(1, 45))
		{
			return;
		}
	}

	bool bReinforce = false;
	bool bAttack = false;
	bool bNoWarPlans = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) == 0);
	bool bAttackBarbarian = false;
	// Thomas SG - AC: Advanced Cargo START	
	bool bIsBarbarian = isBarbarian();
	
	// Count forts as cities
	bool bIsCity = plot()->isCity(true);

	// Cargo if already at war
	int iTargetReinforcementSize = (bIsBarbarian ? AI_stackOfDoomExtra() : 2);

	// Cargo to launch a new invasion
	int iTargetInvasionSize = 2*iTargetReinforcementSize;
	// Thomas SG - AC: Advanced Cargo END
	int iCargo = getGroup()->getCargo();
	int iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) + getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA);

	AreaAITypes eAreaAIType = area()->getAreaAIType(getTeam());
	bool bLandWar = !bIsBarbarian && ((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING));

	// Plot danger case handled above

	if( hasCargo() && (getUnitAICargo(UNITAI_SETTLE) > 0 || getUnitAICargo(UNITAI_WORKER) > 0) )
	{
		// Dump inappropriate load at first oppurtunity after pick up
		if( bIsCity && (plot()->getOwnerINLINE() == getOwnerINLINE()) )
		{		
			getGroup()->unloadAll();
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
		else
		{
			if( !isFull() )
			{
				if(AI_pickupStranded(NO_UNITAI, 1))
				{
					return;
				}
			}

			if (AI_retreatToCity(true))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}
		}
	}

	if (bIsCity)
	{
		CvCity* pCity = plot()->getPlotCity();

		if( pCity != NULL && (plot()->getOwnerINLINE() == getOwnerINLINE()) ) 
		{
			// split out galleys from stack of ocean capable ships
			if( GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType()) == 0 && getGroup()->getNumUnits() > 1 )
			{
				getGroup()->AI_separateImpassable();
			}

			// galleys with upgrade available should get that ASAP
			if( GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType()) > 0 )
			{
				CvCity* pUpgradeCity = getUpgradeCity(false);
				if( pUpgradeCity != NULL && pUpgradeCity == pCity )
				{
					// Wait for upgrade, this unit is top upgrade priority
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}
			}
		}

		if( (iCargo > 0) )
		{
			if( pCity != NULL )
			{
				if( (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) <= 1 )
				{
					if( pCity->getPreviousOwner() != NO_PLAYER )
					{
						// Just captured city, probably from naval invasion.  If area targets, drop cargo and leave so as to not to be lost in quick counter attack
						if( GET_TEAM(getTeam()).countEnemyPowerByArea(plot()->area()) > 0 )
						{
							getGroup()->unloadAll();

							if( iEscorts > 2 )
							{
								if( getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) > 1 && getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) > 0 )
								{
									getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
									getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);

									iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA);
								}
							}
							iCargo = getGroup()->getCargo();
						}
					}
				}
			}
		}

		if( (iCargo > 0) && (iEscorts == 0) )
		{
			if (AI_group(UNITAI_ASSAULT_SEA,-1,-1,-1,/*bIgnoreFaster*/true,false,false,/*iMaxPath*/1,false,/*bCargoOnly*/true,false,MISSIONAI_ASSAULT))
			{
				return;
			}

			if( plot()->plotCount(PUF_isUnitAIType, UNITAI_ESCORT_SEA, -1, getOwnerINLINE(), NO_TEAM, PUF_isGroupHead, -1, -1) > 0 )
			{
				// Loaded but with no escort, wait for escorts in plot to join us
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}

			MissionAITypes eMissionAIType = MISSIONAI_GROUP;
			if( (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 3) > 0) || (GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), 4, false) > 0) )
			{
				// Loaded but with no escort, wait for others joining us soon or avoid dangerous waters
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}
		}

		if (bLandWar)
		{
			if ( iCargo > 0 )
			{
				if( (eAreaAIType == AREAAI_DEFENSIVE) || (pCity != NULL && pCity->AI_isDanger()))
				{
					// Unload cargo when on defense or if small load of troops and can reach enemy city over land (generally less risky)
					getGroup()->unloadAll();
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}
			}

			if ((iCargo >= iTargetReinforcementSize))
			{
				getGroup()->AI_separateEmptyTransports();

				if( !(getGroup()->hasCargo()) )
				{
					// this unit was empty group leader
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}

				// Send ready transports
				if (AI_assaultSeaReinforce(false))
				{
					return;
				}

				if( iCargo >= iTargetInvasionSize )
				{
					if (AI_assaultSeaTransport(false))
					{
						return;
					}
				}
			}
		}
		else
		{
			// Thomas SG - AC: Advanced Cargo START		
			if ( (eAreaAIType == AREAAI_ASSAULT) )
			{
				if( iCargo >= iTargetInvasionSize )
				{
					bAttack = true;
				}
			}
			
			if( (eAreaAIType == AREAAI_ASSAULT) || (eAreaAIType == AREAAI_ASSAULT_ASSIST) )
			{
				{
					if( (bFull && iCargo > totalCargoSpace()) || (iCargo >= iTargetReinforcementSize) )
					{
						bReinforce = true;
					}
				}			
			}
			// Thomas SG - AC: Advanced Cargo END			
		}

		if( !bAttack && !bReinforce && (plot()->getTeam() == getTeam()) )
		{
			if( iEscorts > 3 && iEscorts > (2*getGroup()->countNumUnitAIType(UNITAI_ASSAULT_SEA)) )
			{
				// If we have too many escorts, try freeing some for others
				getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
				getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);

				iEscorts = getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA);
				if( iEscorts > 3 && iEscorts > (2*getGroup()->countNumUnitAIType(UNITAI_ASSAULT_SEA)) )
				{
					getGroup()->AI_separateAI(UNITAI_ESCORT_SEA);
				}
			}
		}

		MissionAITypes eMissionAIType = MISSIONAI_GROUP;
		if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
		{
			// Wait for units which are joining our group this turn
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}

		if( !bFull )
		{
			if( bAttack )
			{
				eMissionAIType = MISSIONAI_LOAD_ASSAULT;
				if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
				{
					// Wait for cargo which will load this turn
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}
			}
			else if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_ASSAULT) > 0 )
			{
				// Wait for cargo which is on the way
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}
		}

		if( !bAttack && !bReinforce )
		{
			if ( iCargo > 0 )
			{
				if (AI_group(UNITAI_ASSAULT_SEA,-1,-1,-1,/*bIgnoreFaster*/true,false,false,/*iMaxPath*/5,false,/*bCargoOnly*/true,false,MISSIONAI_ASSAULT))
				{
					return;
				}
			}
			else if (plot()->getTeam() == getTeam() && getGroup()->getNumUnits() > 1)
			{
				CvCity* pCity = plot()->getPlotCity();
				if( pCity != NULL && (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) > 10 )
				{
					if( pCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_ATTACK_CITY, -1, getOwnerINLINE()) < iTargetReinforcementSize )
					{
						// Not attacking, no cargo so release any escorts, attack ships, etc and split transports
						getGroup()->AI_makeForceSeparate();
					}
				}
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
/************************************************************************************************/
/* REVOLUTIONDCM                             05/24/08                                Glider1    */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - sea bombard AI formally DCM 1.7 AI_RbombardCity()
	// Dale - RB: Field Bombard START
	//if (AI_RbombardCity())
	//{
	//	return;
	//}
	if (AI_RbombardNaval())
	{
		return;
	}
	// Dale - RB: Field Bombard END

	// Dale - ARB: Archer Bombard START
	if (AI_Abombard())
	{
		return;
	}
	// Dale - ARB: Archer Bombard END	
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                    Glider1    */
/************************************************************************************************/
	

	
	if (!bIsCity)
	{
		if( iCargo >= iTargetInvasionSize )
		{
			bAttack = true;
		}
		// Thomas SG - AC: Advanced Cargo START	
		{
			if ((iCargo >= iTargetReinforcementSize) || (bFull && iCargo > totalCargoSpace()))
			{
				bReinforce = true;
			}
		}
// Thomas SG - AC: Advanced Cargo END		
		CvPlot* pAdjacentPlot = NULL;
		for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
		{
			pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
			if( pAdjacentPlot != NULL )
			{
				if( iCargo > 0 )
				{
					CvCity* pAdjacentCity = pAdjacentPlot->getPlotCity();
					if( pAdjacentCity != NULL && pAdjacentCity->getOwner() == getOwnerINLINE() && pAdjacentCity->getPreviousOwner() != NO_PLAYER )
					{
						if( (GC.getGameINLINE().getGameTurn() - pAdjacentCity->getGameTurnAcquired()) < 5 )
						{
							// If just captured city and we have some cargo, dump units in city
							if ( getGroup()->pushMissionInternal(MISSION_MOVE_TO, pAdjacentPlot->getX_INLINE(), pAdjacentPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pAdjacentPlot) )
							{
								return;
							}
						}
					}
				}
				else 
				{
					if (pAdjacentPlot->isOwned() && isEnemy(pAdjacentPlot->getTeam()))
					{
						if( pAdjacentPlot->getNumDefenders(getOwnerINLINE()) > 2 )
						{
							// if we just made a dropoff in enemy territory, release sea bombard units to support invaders
							if ((getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) + getGroup()->countNumUnitAIType(UNITAI_RESERVE_SEA)) > 0)
							{
								bool bMissionPushed = false;
								
								if (AI_seaBombardRange(1))
								{
									bMissionPushed = true;
								}

								CvSelectionGroup* pOldGroup = getGroup();

								//Release any Warships to finish the job.
								getGroup()->AI_separateAI(UNITAI_ATTACK_SEA);
								getGroup()->AI_separateAI(UNITAI_RESERVE_SEA);

/************************************************************************************************/
/* UNOFFICIAL_PATCH                       05/11/09                                jdog5000      */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
/* original bts code
					if (pOldGroup == getGroup() && getUnitType() == UNITAI_ASSAULT_SEA)
					{
						if (AI_retreatToCity(true))
						{
							bMissionPushed = true;
						}
					}
*/
								// Fixed bug in next line with checking unit type instead of unit AI
								if (pOldGroup == getGroup() && AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
								{
									// Need to be sure all units can move
									if( getGroup()->canAllMove() )
									{
										if (AI_retreatToCity(true))
										{
											bMissionPushed = true;
										}
									}
								}
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/


								if (bMissionPushed)
								{
									return;
								}
							}
						}
					}
				}
			}
		}
		
		if(iCargo > 0)
		{
			MissionAITypes eMissionAIType = MISSIONAI_GROUP;
			if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
			{
				if( iEscorts < GET_PLAYER(getOwnerINLINE()).AI_getWaterDanger(plot(), 2, false) )
				{
					// Wait for units which are joining our group this turn (hopefully escorts)
					getGroup()->pushMission(MISSION_SKIP);
					return;
				}
			}
		}
	}

	if (bIsBarbarian)
	{
		if (getGroup()->isFull() || iCargo > iTargetInvasionSize)
		{
			if (AI_assaultSeaTransport(false))
			{
				return;
			}
		}
		else
		{
			if (AI_pickup(UNITAI_ATTACK_CITY, true, 5))
			{
				return;
			}

			if (AI_pickup(UNITAI_ATTACK, true, 5))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if( !(getGroup()->getCargo()) )
			{
				AI_barbAttackSeaMove();
				return;
			}

			if( AI_safety() )
			{
				return;
			}

			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}
	else
	{
		if (bAttack || bReinforce)
		{
			if( bIsCity )
			{
				getGroup()->AI_separateEmptyTransports();
			}

			if( !(getGroup()->hasCargo()) )
			{
				// this unit was empty group leader
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}

			FAssert(getGroup()->hasCargo());

			//BBAI TODO: Check that group has escorts, otherwise usually wait

			if( bAttack )
			{
				if( bReinforce && (AI_getBirthmark()%2 == 0) )
				{
					if (AI_assaultSeaReinforce())
					{
						return;
					}
					bReinforce = false;
				}

				if (AI_assaultSeaTransport())
				{
					return;
				}
			}

			// If not enough troops for own invasion, 
			if( bReinforce )
			{
				if (AI_assaultSeaReinforce())
				{
					return;
				}	
			}
		}

		if( bNoWarPlans && (iCargo >= iTargetReinforcementSize) )
		{
			bAttackBarbarian = true;

			getGroup()->AI_separateEmptyTransports();

			if( !(getGroup()->hasCargo()) )
			{
				// this unit was empty group leader
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}

			FAssert(getGroup()->hasCargo());
			if (AI_assaultSeaReinforce(bAttackBarbarian))
			{
				return;
			}

			FAssert(getGroup()->hasCargo());
			if (AI_assaultSeaTransport(bAttackBarbarian))
			{
				return;
			}
		}
	}

	if ((bFull || bReinforce) && !bAttack)
	{
		// Group with nearby transports with units on board
		if (AI_group(UNITAI_ASSAULT_SEA, -1, /*iMaxOwnUnitAI*/ -1, -1, true, false, false, 2, false, true, false, MISSIONAI_ASSAULT))
		{
			return;
		}

		if (AI_group(UNITAI_ASSAULT_SEA, -1, -1, -1, true, false, false, 10, false, true, false, MISSIONAI_ASSAULT))
		{
			return;
		}
	}
	else if( !bFull )
	{
// Thomas SG - AC: Advanced Cargo START
		bool bHasOneLoad = false;
		{
			bHasOneLoad = (getGroup()->getCargo() >= totalCargoSpace()-getTotalSpecialCargoSpace());
		}
// Thomas SG - AC: Advanced Cargo END	
		bool bHasCargo = getGroup()->hasCargo();

		if (AI_pickup(UNITAI_ATTACK_CITY, !bHasCargo, (bHasOneLoad ? 3 : 7)))
		{
			return;
		}

		if (AI_pickup(UNITAI_ATTACK, !bHasCargo, (bHasOneLoad ? 3 : 7)))
		{
			return;
		}
		
		if (AI_pickup(UNITAI_COUNTER, !bHasCargo, (bHasOneLoad ? 3 : 7)))
		{
			return;
		}

		if (AI_pickup(UNITAI_ATTACK_CITY, !bHasCargo))
		{
			return;
		}

		if( !bHasCargo )
		{
			if(AI_pickupStranded(UNITAI_ATTACK_CITY))
			{
				return;
			}

			if(AI_pickupStranded(UNITAI_ATTACK))
			{
				return;
			}

			if(AI_pickupStranded(UNITAI_COUNTER))
			{
				return;
			}

			if( (getGroup()->countNumUnitAIType(AI_getUnitAIType()) == 1) )
			{
				// Try picking up any thing
				if(AI_pickupStranded())
				{
					return;
				}
			}
		}
	}

	if (bIsCity && bLandWar && getGroup()->hasCargo())
	{
		// Enemy units in this player's territory
		if( GET_PLAYER(getOwnerINLINE()).AI_countNumAreaHostileUnits(area(),true,false,false,false, plot(), 15) > (getGroup()->getCargo()/2))
		{
			getGroup()->unloadAll();
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}
	
	if (AI_retreatToCity(true))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


void CvUnitAI::AI_settlerSeaMove()
{
	PROFILE_FUNC();
	
	bool bEmpty = !getGroup()->hasCargo();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
		{
			if( bEmpty )
			{
				if (AI_anyAttack(1, 65))
				{
					return;
				}
			}

			// Retreat to primary area first
			if (AI_retreatToCity(true))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (bEmpty)
	{
		if (AI_anyAttack(1, 65))
		{
			return;
		}
		if (AI_anyAttack(1, 40))
		{
			return;
		}		
	}
	
	int iSettlerCount = getUnitAICargo(UNITAI_SETTLE);
	int iWorkerCount = getUnitAICargo(UNITAI_WORKER);

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      12/07/08                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	if( hasCargo() && (iSettlerCount == 0) && (iWorkerCount == 0))
	{
		// Dump troop load at first oppurtunity after pick up
		if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
		{
			getGroup()->unloadAll();
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
		else
		{
			if( !(isFull()) )
			{
				if(AI_pickupStranded(NO_UNITAI, 1))
				{
					return;
				}
			}

			if (AI_retreatToCity(true))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
// Thomas SG - AC: Advanced Cargo START
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      06/02/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/
	// Don't send transport with settler and no defense
	{
		if( (iSettlerCount > 0) && (iSettlerCount + iWorkerCount == (totalCargoSpace()- getTotalSpecialCargoSpace()) ))
		{
			// No defenders for settler
			if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
			{
				getGroup()->unloadAll();
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}
		}
	}
// Thomas SG - AC: Advanced Cargo END	
	if ((iSettlerCount > 0) && (isFull() ||
			((getUnitAICargo(UNITAI_CITY_DEFENSE) > 0) &&
			 (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) == 0))))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		if (AI_settlerSeaTransport())
		{
			return;
		}
	}
	else if ((getTeam() != plot()->getTeam()) && bEmpty)
	{
		if (AI_pillageRange(3))
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	if (plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() && !hasCargo())
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	{
		AreaAITypes eAreaAI = area()->getAreaAIType(getTeam());
		if ((eAreaAI == AREAAI_ASSAULT) || (eAreaAI == AREAAI_ASSAULT_MASSING))
		{
			CvArea* pWaterArea = plot()->waterArea();
			FAssert(pWaterArea != NULL);
			if (pWaterArea != NULL)
			{
				if (GET_PLAYER(getOwnerINLINE()).AI_totalWaterAreaUnitAIs(pWaterArea, UNITAI_SETTLER_SEA) > 1)
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_ASSAULT_SEA, pWaterArea) > 0)
					{
						AI_setUnitAIType(UNITAI_ASSAULT_SEA);
						AI_assaultSeaMove();
						return;
					}
				}
			}
		}
	}
	
	if ((iWorkerCount > 0)
		&& GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) == 0)
	{
		if (isFull() || (iSettlerCount == 0))
		{
			if (AI_settlerSeaFerry())
			{
				return;
			}
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/
/* original bts code
	if (AI_pickup(UNITAI_SETTLE))
	{
		return;
	}
*/
	if( !(getGroup()->hasCargo()) )
	{
		if(AI_pickupStranded(UNITAI_SETTLE))
		{
			return;
		}
	}

	if( !(getGroup()->isFull()) )
	{
		if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SETTLER) > 0 )
		{
			// Wait for units on the way
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	
// Thomas SG - AC: Advanced Cargo START
		{
			if( iSettlerCount > 0 )
			{
				if (AI_pickup(UNITAI_CITY_DEFENSE))
				{
					return;
				}
			}
			else if( totalCargoSpace() - getTotalSpecialCargoSpace() - 2 >= getCargo() + iWorkerCount )
			{
				if (AI_pickup(UNITAI_SETTLE, true))
				{
					return;
				}
			}
		}
// Thomas SG - AC: Advanced Cargo END
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/	
	
	if ((GC.getGame().getGameTurn() - getGameTurnCreated()) < 8)
	{
		if ((plot()->getPlotCity() == NULL) || GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(plot()->area(), UNITAI_SETTLE) == 0)
		{
			if (AI_explore())
			{
				return;
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/18/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
	if (AI_pickup(UNITAI_WORKER))
	{
		return;
	}
*/
	if( !getGroup()->hasCargo() )
	{
		// Rescue stranded non-settlers
		if(AI_pickupStranded())
		{
			return;
		}
	}
	
	//	Koshling - old condition here was broken for transports with a max capacity of 1 (canoes),
	//	and (after readiong the old code) I think more generally anyway.  Effect was it repeatedly went
	//	through here without ever actually wanting to load a settler (which it never does without an
	//	escort unit also) and wound up giving no orders at all to this unit, then looping over this 100 times
	//	a ta higher level before giving up and skipping moves for this unit.
	//if( cargoSpace() - 2 < getCargo() + iWorkerCount )
	if( cargoSpace() > 1 && cargoSpace() - getCargo() < 2 && iWorkerCount > 0 )
	{
		// If full of workers and not going anywhere, dump them if a settler is available
		if( (iSettlerCount == 0) && (plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_SETTLE, -1, getOwnerINLINE(), NO_TEAM, PUF_isFiniteRange) > 0) )
		{
			getGroup()->unloadAll();

			if (AI_pickup(UNITAI_SETTLE, true))
			{
				return;
			}

			return;
		}
	}
	
	if( !(getGroup()->isFull()) )
	{
		if (AI_pickup(UNITAI_WORKER))
		{
			return;
		}
	}

	// Carracks cause problems for transport upgrades, galleys can't upgrade to them and they can't
	// upgrade to galleons.  Scrap galleys, switch unit AI for stuck Carracks.
	if( plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE() )
	{
		//
		{
			UnitTypes eBestSettlerTransport = NO_UNIT;
			GET_PLAYER(getOwnerINLINE()).AI_bestCityUnitAIValue(AI_getUnitAIType(), NULL, &eBestSettlerTransport);
			if( eBestSettlerTransport != NO_UNIT )
			{
				if( eBestSettlerTransport != getUnitType() && GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(eBestSettlerTransport) == 0 )
				{
					UnitClassTypes ePotentialUpgradeClass = (UnitClassTypes)GC.getUnitInfo(eBestSettlerTransport).getUnitClassType();
					if( !upgradeAvailable(getUnitType(), ePotentialUpgradeClass) )
					{
						getGroup()->unloadAll();

						if( GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType()) > 0 )
						{
							scrap();
							return;
						}
						else
						{
							CvArea* pWaterArea = plot()->waterArea();
							FAssert(pWaterArea != NULL);
							if (pWaterArea != NULL)
							{
								if( GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_EXPLORE_SEA) == 0 )
								{
									if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_EXPLORE_SEA, pWaterArea) > 0)
									{
										AI_setUnitAIType(UNITAI_EXPLORE_SEA);
										AI_exploreSeaMove();
										return;
									}
								}

								if( GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_SPY_SEA) == 0 )
								{
									if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_SPY_SEA, area()) > 0)
									{
										AI_setUnitAIType(UNITAI_SPY_SEA);
										AI_spySeaMove();
										return;
									}
								}

								if( GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_MISSIONARY_SEA) == 0 )
								{
									if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_MISSIONARY_SEA, area()) > 0)
									{
										AI_setUnitAIType(UNITAI_MISSIONARY_SEA);
										AI_missionarySeaMove();
										return;
									}
								}

								if (GET_PLAYER(getOwnerINLINE()).AI_unitValue(getUnitType(), UNITAI_ATTACK_SEA, pWaterArea) > 0)
								{
									AI_setUnitAIType(UNITAI_ATTACK_SEA);
									AI_attackSeaMove();
									return;
								}
							}
						}
					}
				}
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		
	if (AI_retreatToCity(true))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_missionarySeaMove()
{
	PROFILE_FUNC();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
		{
			// Retreat to primary area first
			if (AI_retreatToCity(true))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (getUnitAICargo(UNITAI_MISSIONARY) > 0)
	{
		if (AI_specialSeaTransportMissionary())
		{
			return;
		}
	}
	else if (!(getGroup()->hasCargo()))
	{
		if (AI_pillageRange(4))
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/14/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	if( !(getGroup()->isFull()) )
	{
		if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SPECIAL) > 0 )
		{
			// Wait for units on the way
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}

	if (AI_pickup(UNITAI_MISSIONARY, true))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/	
	
	if (AI_explore())
	{
		return;
	}

	if (AI_retreatToCity(true))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_spySeaMove()
{
	PROFILE_FUNC();

	CvCity* pCity;

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
		{
			// Retreat to primary area first
			if (AI_retreatToCity(true))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (getUnitAICargo(UNITAI_SPY) > 0)
	{
		if (AI_specialSeaTransportSpy())
		{
			return;
		}

		pCity = plot()->getPlotCity();

		if (pCity != NULL)
		{
			if (pCity->getOwnerINLINE() == getOwnerINLINE())
			{
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pCity->plot());
				return;
			}
		}
	}
	else if (!(getGroup()->hasCargo()))
	{
		if (AI_pillageRange(5))
		{
			return;
		}
	}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/14/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
	if( !(getGroup()->isFull()) )
	{
		if( GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_LOAD_SPECIAL) > 0 )
		{
			// Wait for units on the way
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}

	if (AI_pickup(UNITAI_SPY, true))
	{
		return;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/	

	if (AI_retreatToCity(true))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_carrierSeaMove()
{
	PROFILE_FUNC();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
		{
			if (AI_retreatToCity(true))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/
	
	if (AI_heal(50))
	{
		return;
	}

	if (!isEnemy(plot()->getTeam()))
	{
		if (GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, MISSIONAI_GROUP) > 0)
		{
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}
	else
	{
		if (AI_seaBombardRange(1))
		{
			return;
		}
	}
	
	if (AI_group(UNITAI_CARRIER_SEA, -1, /*iMaxOwnUnitAI*/ 1))
	{
		return;
	}

	if (getGroup()->countNumUnitAIType(UNITAI_ATTACK_SEA) + getGroup()->countNumUnitAIType(UNITAI_ESCORT_SEA) == 0)
	{
		if (plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE())
		{
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
		if (AI_retreatToCity())
		{
			return;
		}
	}
		
	if (getCargo() > 0)
	{
		if (AI_carrierSeaTransport())
		{
			return;
		}

		if (AI_blockade())
		{
			return;
		}

		if (AI_shadow(UNITAI_ASSAULT_SEA))
		{
			return;
		}
	}
	
	if (AI_travelToUpgradeCity())
	{
		return;
	}

	if (AI_retreatToCity(true))
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_missileCarrierSeaMove()
{
	PROFILE_FUNC();

	bool bIsStealth = (getInvisibleType() != NO_INVISIBLE);

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						06/14/09	Solver & jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if( getDamage() > 0 )	// extra risk to leaving when wounded
		{
			iOurDefense *= 2;
		}

		if( iEnemyOffense > iOurDefense/4 || iOurDefense == 0 ) //prioritize getting outta there
		{
			if (AI_shadow(UNITAI_ASSAULT_SEA, 1, 50, false, true, 1))
			{
				return;
			}

			if (AI_retreatToCity())
			{
				return;
			}

			if (AI_safety())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/
	
	if (plot()->isCity() && plot()->getTeam() == getTeam())
	{
		if (AI_heal())
		{
			return;
		}
	}
	
	if (((plot()->getTeam() != getTeam()) && getGroup()->hasCargo()) || getGroup()->AI_isFull())
	{
		if (bIsStealth)
		{
			if (AI_carrierSeaTransport())
			{
				return;
			}
		}
		else
		{
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						06/14/09		jdog5000		*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
			if (AI_shadow(UNITAI_ASSAULT_SEA, 1, 50, true, false, 12))
			{
				return;
			}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/
		
			if (AI_carrierSeaTransport())
			{
				return;
			}
		}
	}
//	if (AI_pickup(UNITAI_ICBM))
//	{
//		return;
//	}
//	
//	if (AI_pickup(UNITAI_MISSILE_AIR))
//	{
//		return;
//	}
	if (AI_retreatToCity())
	{
		return;
	}
	
	getGroup()->pushMission(MISSION_SKIP);
}


void CvUnitAI::AI_attackAirMove()
{
	PROFILE_FUNC();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Air AI																	*/
/********************************************************************************/
	CvCity* pCity = plot()->getPlotCity();
	bool bSkiesClear = true;
	int iDX, iDY;

	// Check for sufficient defenders to stay
	int iDefenders = plot()->plotCount(PUF_canDefend, -1, -1, plot()->getOwner());

	int iAttackAirCount = plot()->plotCount(PUF_canAirAttack, -1, -1, NO_PLAYER, getTeam());
	iAttackAirCount += 2 * plot()->plotCount(PUF_isUnitAIType, UNITAI_ICBM, -1, NO_PLAYER, getTeam());

	if( plot()->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) )
	{
		iDefenders -= 1;
	}

	if( pCity != NULL )
	{
		if( pCity->getDefenseModifier(true) < 40 )
		{
			iDefenders -= 1;
		}

		if( pCity->getOccupationTimer() > 1 )
		{
			iDefenders -= 1;
		}
	}

	if( iAttackAirCount > iDefenders )
	{
		if (AI_airOffensiveCity())
		{
			return;
		}
	}

	// Check for direct threat to current base
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);

		if (iEnemyOffense > iOurDefense || iOurDefense == 0)
		{
			// Too risky, pull back
			if (AI_airOffensiveCity())
			{
				return;
			}

			if( canAirDefend() )
			{
				if (AI_airDefensiveCity())
				{
					return;
				}
			}
		}
		else if( iEnemyOffense > iOurDefense/3 )
		{
			if( getDamage() == 0 )
			{
				if( !getGroup()->hasCollateralDamage() && canAirDefend() )
				{
					if (pCity != NULL)
					{
						// Check for whether city needs this unit to air defend
						if( !(pCity->AI_isAirDefended(true,-1)) )
						{
							getGroup()->pushMission(MISSION_AIRPATROL);
							return;
						}
					}
				}

				// Attack the invaders!
				if (AI_defendBaseAirStrike())
				{
					return;
				}
				
				if (AI_defensiveAirStrike())
				{
					return;
				}

				if (AI_airStrike())
				{
					return;
				}

				// If no targets, no sense staying in risky place
				if (AI_airOffensiveCity())
				{
					return;
				}

				if( canAirDefend() )
				{
					if (AI_airDefensiveCity())
					{
						return;
					}
				}
			}

			if( healTurns(plot()) > 1 )
			{
				// If very damaged, no sense staying in risky place
				if (AI_airOffensiveCity())
				{
					return;
				}

				if( canAirDefend() )
				{
					if (AI_airDefensiveCity())
					{
						return;
					}
				}
			}
			
		}
	}

	if( getDamage() > 0 )
	{
		if (((100*currHitPoints()) / maxHitPoints()) < 40)
		{
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
		else
		{
			CvPlot *pLoopPlot;
			int iSearchRange = airRange();
			for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
			{
				if (!bSkiesClear) break;
				for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
				{
					pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

					if (pLoopPlot != NULL)
					{
						if (bestInterceptor(pLoopPlot) != NULL)
						{
							bSkiesClear = false;
							break;
						}
					}
				}
			}

			if (!bSkiesClear)
			{
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
	CvArea* pArea = area();
	int iAttackValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_ATTACK_AIR, pArea);
	int iCarrierValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_CARRIER_AIR, pArea);
	if (iCarrierValue > 0)
	{
		int iCarriers = kPlayer.AI_totalUnitAIs(UNITAI_CARRIER_SEA);
		if (iCarriers > 0)
		{
			UnitTypes eBestCarrierUnit = NO_UNIT;  
			kPlayer.AI_bestAreaUnitAIValue(UNITAI_CARRIER_SEA, NULL, &eBestCarrierUnit);
			if (eBestCarrierUnit != NO_UNIT)
			{
// Thomas SG - AC: Advanced Cargo START
				int iCarrierAirNeeded = 0;
				{
					iCarrierAirNeeded = iCarriers * std::max(0,GC.getUnitInfo(eBestCarrierUnit).getTotalSpecialCargoSpace()-1);
				}
// Thomas SG - AC: Advanced Cargo END			
				if (kPlayer.AI_totalUnitAIs(UNITAI_CARRIER_AIR) < iCarrierAirNeeded)
				{
					AI_setUnitAIType(UNITAI_CARRIER_AIR);
					getGroup()->pushMission(MISSION_SKIP);
					return;		
				}
			}
		}
	}
	
	int iDefenseValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_DEFENSE_AIR, pArea);
	if (iDefenseValue > iAttackValue)
	{
		if (kPlayer.AI_bestAreaUnitAIValue(UNITAI_ATTACK_AIR, pArea) > iAttackValue)
		{
			AI_setUnitAIType(UNITAI_DEFENSE_AIR);
			getGroup()->pushMission(MISSION_SKIP);
			return;	
		}
	}

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/6/08			jdog5000		*/
/* 																			*/
/* 	Air AI																	*/
/********************************************************************************/
	/* original BTS code
	if (AI_airBombDefenses())
	{
		return;
	}

	if (GC.getGameINLINE().getSorenRandNum(4, "AI Air Attack Move") == 0)
	{
		if (AI_airBombPlots())
		{
			return;
		}
	}

	if (AI_airStrike())
	{
		return;
	}
	
	if (canAirAttack())
	{
		if (AI_airOffensiveCity())
		{
			return;
		}
	}
	
	if (canRecon(plot()))
	{
		if (AI_exploreAir())
		{
			return;
		}
	}

	if (canAirDefend())
	{
		getGroup()->pushMission(MISSION_AIRPATROL);
		return;
	}
	*/
	bool bDefensive = false;
	if( pArea != NULL )
	{
		bDefensive = pArea->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE;
	}

	if (GC.getGameINLINE().getSorenRandNum(bDefensive ? 3 : 6, "AI Air Attack Move") == 0)
	{
		if( AI_defensiveAirStrike() )
		{
			return;
		}
	}

	if (GC.getGameINLINE().getSorenRandNum(4, "AI Air Attack Move") == 0)
	{
		// only moves unit in a fort
		if (AI_travelToUpgradeCity())
		{
			return;
		}
	}

	// Support ground attacks
	if (AI_airBombDefenses())
	{
		return;
	}

	if (GC.getGameINLINE().getSorenRandNum(bDefensive ? 6 : 4, "AI Air Attack Move") == 0)
	{
		if (AI_airBombPlots())
		{
			return;
		}
	}

	if (AI_airStrike())
	{
		return;
	}
	
	if (canAirAttack())
	{
		if (AI_airOffensiveCity())
		{
			return;
		}
	}
	else
	{
		if( canAirDefend() )
		{
			if (AI_airDefensiveCity())
			{
				return;
			}
		}
	}

	// BBAI TODO: Support friendly attacks on common enemies, if low risk?

	if (canAirDefend())
	{
		if( bDefensive || GC.getGameINLINE().getSorenRandNum(2, "AI Air Attack Move") == 0 )
		{
			getGroup()->pushMission(MISSION_AIRPATROL);
			return;
		}
	}
	
	if (canRecon(plot()))
	{
		if (AI_exploreAir())
		{
			return;
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/
	

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_defenseAirMove()
{
	PROFILE_FUNC();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Air AI																	*/
/********************************************************************************/
	CvCity* pCity = plot()->getPlotCity();

	int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
	
	// includes forts
	if (plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
	
		if (3*iEnemyOffense > 4*iOurDefense || iOurDefense == 0)
		{
			// Too risky, pull out
			// AI_airDefensiveCity will leave some air defense, pull extras out
			if (AI_airDefensiveCity())
			{
				return;
			}
		}
		else if ( iEnemyOffense > iOurDefense/3 )
		{
			if (getDamage() > 0)
			{
				if( healTurns(plot()) > 1 + GC.getGameINLINE().getSorenRandNum(2, "AI Air Defense Move") )
				{
					// Can't help current situation, only risk losing unit
					if (AI_airDefensiveCity())
					{
						return;
					}
				}

				// Stay to defend in the future
				getGroup()->pushMission(MISSION_SKIP);
				return;
			}

			if (canAirDefend() && pCity != NULL)
			{
				// Check for whether city needs this unit to air defend
				if( !(pCity->AI_isAirDefended(true,-1)) )
				{
					getGroup()->pushMission(MISSION_AIRPATROL);
					return;
				}

				// Consider adding extra defenders
				if( !getGroup()->hasCollateralDamage() && (!pCity->AI_isAirDefended(false,-2)) )
				{
					if( GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") == 0 )
					{
						getGroup()->pushMission(MISSION_AIRPATROL);
						return;
					}
				}
			}

			// Attack the invaders!
			if (AI_defendBaseAirStrike())
			{
				return;
			}
			
			if (AI_defensiveAirStrike())
			{
				return;
			}

			if (AI_airStrike())
			{
				return;
			}

			if (AI_airDefensiveCity())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (getDamage() > 0)
	{
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}
	
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/17/08	Solver & jdog5000	*/
/* 																			*/
/* 	Air AI																	*/
/********************************************************************************/
	/* original BTS code
	if ((GC.getGameINLINE().getSorenRandNum(2, "AI Air Defense Move") == 0))
	{
		if ((pCity != NULL) && pCity->AI_isDanger())
		{
			if (AI_airStrike())
			{
				return;
			}
		}
		else
		{
			if (AI_airBombDefenses())
			{
				return;
			}

			if (AI_airStrike())
			{
				return;
			}
			
			if (AI_getBirthmark() % 2 == 0)
			{
				if (AI_airBombPlots())
				{
					return;
				}
			}
		}

		if (AI_travelToUpgradeCity())
		{
			return;
		}
	}

	bool bNoWar = (GET_TEAM(getTeam()).getAtWarCount(false) == 0);
	
	if (canRecon(plot()))
	{
		if (GC.getGame().getSorenRandNum(bNoWar ? 2 : 4, "AI defensive air recon") == 0)
		{
			if (AI_exploreAir())
			{
				return;
			}
		}
	}

	if (AI_airDefensiveCity())
	{
		return;
	}
	*/
	if((GC.getGameINLINE().getSorenRandNum(4, "AI Air Defense Move") == 0))
	{
		// only moves unit in a fort
		if (AI_travelToUpgradeCity())
		{
			return;
		}
	}

	if( canAirDefend() )
	{
		// Check for whether city needs this unit for base air defenses
		int iBaseAirDefenders = 0;

		if( iEnemyOffense > 0 )
		{
			iBaseAirDefenders++;
		}

		if( pCity != NULL )
		{
			iBaseAirDefenders += pCity->AI_neededAirDefenders()/2;
		}
		
		if( plot()->countAirInterceptorsActive(getTeam()) < iBaseAirDefenders )
		{
			getGroup()->pushMission(MISSION_AIRPATROL);
			return;
		}
	}

	CvArea* pArea = area();
	bool bDefensive = false;
	bool bOffensive = false;

	if( pArea != NULL )
	{
		bDefensive = (pArea->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE);
		bOffensive = (pArea->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
	}

	if( (iEnemyOffense > 0) || bDefensive )
	{
		if( canAirDefend() )
		{
			if( pCity != NULL )
			{
				// Consider adding extra defenders
				if( !(pCity->AI_isAirDefended(false,-1)) )
				{
					if ((GC.getGameINLINE().getSorenRandNum((bOffensive ? 3 : 2), "AI Air Defense Move") == 0))
					{
						getGroup()->pushMission(MISSION_AIRPATROL);
						return;
					}
				}
			}
			else
			{
				if ((GC.getGameINLINE().getSorenRandNum((bOffensive ? 3 : 2), "AI Air Defense Move") == 0))
				{
					getGroup()->pushMission(MISSION_AIRPATROL);
					return;
				}
			}
		}

		if((GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") > 0))
		{
			if (AI_defensiveAirStrike())
			{
				return;
			}

			if (AI_airStrike())
			{
				return;
			}
		}
	}
	else
	{
		if ((GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") > 0))
		{
			// Clear out any enemy fighters, support offensive units
			if (AI_airBombDefenses())
			{
				return;
			}

			if (GC.getGameINLINE().getSorenRandNum(3, "AI Air Defense Move") == 0)
			{
				// Hit enemy land stacks near our cities
				if (AI_defensiveAirStrike())
				{
					return;
				}
			}

			if (AI_airStrike())
			{
				return;
			}
			
			if (AI_getBirthmark() % 2 == 0 || bOffensive)
			{
				if (AI_airBombPlots())
				{
					return;
				}
			}
		}
	}

	if (AI_airDefensiveCity())
	{
		return;
	}

	// BBAI TODO: how valuable is recon information to AI in war time?	
	if (canRecon(plot()))
	{
		if (GC.getGame().getSorenRandNum(bDefensive ? 6 : 3, "AI defensive air recon") == 0)
		{
			if (AI_exploreAir())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

	if (canAirDefend())
	{
		getGroup()->pushMission(MISSION_AIRPATROL);
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_carrierAirMove()
{
	PROFILE_FUNC();

	// XXX maybe protect land troops?

	if (getDamage() > 0)
	{
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}

	if (isCargo())
	{
		int iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Carrier Move");
		
		if (iRand == 2 && canAirDefend())
		{
			getGroup()->pushMission(MISSION_AIRPATROL);
			return;
		}
		else if (AI_airBombDefenses())
		{
			return;
		}
		else if (iRand == 1)
		{
			if (AI_airBombPlots())
			{
				return;
			}
			
			if (AI_airStrike())
			{
				return;
			}
		}
		else
		{
			if (AI_airStrike())
			{
				return;
			}
			
			if (AI_airBombPlots())
			{
				return;
			}
		}

		if (AI_travelToUpgradeCity())
		{
			return;
		}

		if (canAirDefend())
		{
			getGroup()->pushMission(MISSION_AIRPATROL);
			return;
		}
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}

	if (AI_airCarrier())
	{
		return;
	}

	if (AI_airDefensiveCity())
	{
		return;
	}

	if (canAirDefend())
	{
		getGroup()->pushMission(MISSION_AIRPATROL);
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_missileAirMove()
{
	PROFILE_FUNC();

	CvCity* pCity = plot()->getPlotCity();

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						10/21/08	Solver & jdog5000	*/
/* 																			*/
/* 	Air AI																	*/
/********************************************************************************/
	// includes forts
	if (!isCargo() && plot()->isCity(true))
	{
		int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
		int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
		
		if (iEnemyOffense > (iOurDefense/2) || iOurDefense == 0)
		{
			if (AI_airOffensiveCity())
			{
				return;
			}
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/
	
	if (isCargo())
	{
		int iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Missile plot bombing");
		if (iRand != 0)
		{
			if (AI_airBombPlots())
			{
				return;
			}
		}

		iRand = GC.getGameINLINE().getSorenRandNum(3, "AI Air Missile Carrier Move");
		if (iRand == 0)
		{
			if (AI_airBombDefenses())
			{
				return;
			}
			
			if (AI_airStrike())
			{
				return;
			}
		}
		else
		{	
			if (AI_airStrike())
			{
				return;
			}
			
			if (AI_airBombDefenses())
			{
				return;
			}
		}
		
		if (AI_airBombPlots())
		{
			return;
		}
		
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}
	
	if (AI_airStrike())
	{
		return;
	}
	
	if (AI_missileLoad(UNITAI_MISSILE_CARRIER_SEA))
	{
		return;
	}
	
	if (AI_missileLoad(UNITAI_RESERVE_SEA, 1))
	{
		return;
	}
	
	if (AI_missileLoad(UNITAI_ATTACK_SEA, 1))
	{
		return;
	}

	if (AI_airBombDefenses())
	{
		return;
	}

	if (!isCargo())
	{
		if (AI_airOffensiveCity())
		{
			return;
		}
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_networkAutomated()
{
	FAssertMsg(canBuildRoute(), "canBuildRoute is expected to be true");

	if (!(getGroup()->canDefend()))
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
		//if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
		if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		{
			if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
			{
				return;
			}
		}
	}

	if (AI_improveBonus(20))
	{
		return;
	}

	if (AI_improveBonus(10))
	{
		return;
	}

	if (AI_connectBonus())
	{
		return;
	}

	if (AI_connectCity())
	{
		return;
	}

	if (AI_improveBonus())
	{
		return;
	}

	if (AI_routeTerritory(true))
	{
		return;
	}

	if (AI_connectBonus(false))
	{
		return;
	}

	if (AI_routeCity())
	{
		return;
	}

	if (AI_routeTerritory())
	{
		return;
	}
	
	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


void CvUnitAI::AI_cityAutomated()
{
	CvCity* pCity;

	if (!(getGroup()->canDefend()))
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
		//if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot()) > 0)
		if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(plot()))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		{
			if (AI_retreatToCity()) // XXX maybe not do this??? could be working productively somewhere else...
			{
				return;
			}
		}
	}

	pCity = NULL;

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		pCity = plot()->getWorkingCity();
	}

	if (pCity == NULL)
	{
		pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE()); // XXX do team???
	}

	if (pCity != NULL)
	{
		if (AI_improveCity(pCity))
		{
			return;
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}


// XXX make sure we include any new UnitAITypes...
int CvUnitAI::AI_promotionValue(PromotionTypes ePromotion)
{
	return GET_PLAYER(getOwnerINLINE()).AI_promotionValue(ePromotion, getUnitType(), this, AI_getUnitAIType());
	// AIAndy: There is a return as first statement, anything below here will not be executed so might as well be commented out to avoid confusion
//	int iValue;
//	int iTemp;
//	int iExtra;
//	int iI;
//
//	iValue = 0;
//
///************************************************************************************************/
///* SUPER SPIES                            05/24/08                                TSheep        */
///*                                                                                              */
///*                                                                                              */
///************************************************************************************************/
//	//TSHEEP Setup AI values for promotions
//	if(isSpy())
//	{
//	/*********************************************************************************************/
//	/* REVOLUTIONDCM				24/09/09						glider1						 */
//	/**																							 */
//	/*********************************************************************************************/
//	//Readjust promotion choices favouring security, deception, logistics, escape, improvise,
//	//filling in other promotions very lightly because the AI does not yet have situational awareness
//	//when using spy promotions at the moment of mission execution.
//
//		//Logistics
//		//I & III
//		iValue += (GC.getPromotionInfo(ePromotion).getMovesChange()*20);
//		//II
//		if (GC.getPromotionInfo(ePromotion).isEnemyRoute()) iValue += 20;
//		iValue += (GC.getPromotionInfo(ePromotion).getMoveDiscountChange()*10);
//		//total 20, 30, 20 points
//
//		//Deception
//		if (GC.getPromotionInfo(ePromotion).getEvasionChange())
//		{
//			//Lean towards more deception if deception is already present
//			iValue += ((GC.getPromotionInfo(ePromotion).getEvasionChange() * 2) + evasionProbability());
//		}//total 20, 30, 40 points
//
//		//Security
//		iValue += (GC.getPromotionInfo(ePromotion).getVisibilityChange()*10);
//		//Lean towards more security if security is already present
//		iValue += (GC.getPromotionInfo(ePromotion).getInterceptChange() + currInterceptionProbability());
//		//total 20, 30, 40 points
//
//		//Escape
//		if (GC.getPromotionInfo(ePromotion).getWithdrawalChange())
//		{
//			iValue += 30;
//		}
//
//		//Improvise
//		if (GC.getPromotionInfo(ePromotion).getUpgradeDiscount())
//		{
//			iValue += 20;
//		}
//		
//		//Loyalty
//		if (GC.getPromotionInfo(ePromotion).isAlwaysHeal()) 
//		{
//			iValue += 15;
//		}
//
//		//Instigator
//		//I & II
//		if (GC.getPromotionInfo(ePromotion).getEnemyHealChange()) 
//		{
//			iValue += 15;
//		}
//		//III
//		if (GC.getPromotionInfo(ePromotion).getNeutralHealChange())
//		{
//			iValue += 15;
//		}
//
//		//Alchemist
//		if (GC.getPromotionInfo(ePromotion).getFriendlyHealChange())
//		{
//			iValue += 15;
//		}
//
//		if (iValue > 0)
//		{
//			iValue += GC.getGameINLINE().getSorenRandNum(15, "AI Promote");
//		}
//
//		return iValue;
//	/****************************************************************************************/
//	/* REVOLUTIONDCM				END      						glider1                 */
//	/****************************************************************************************/
//	}
///********************************************************************************************/
///* SUPER SPIES                     END                             TSheep                  */
/////********************************************************************************************/
//
///*****************************************************************************************************/
///**  Author: TheLadiesOgre                                                                          **/
///**  Date: 16.09.2009                                                                               **/
///**  ModComp: TLOTags                                                                               **/
///**  Reason Added: Set AI Value for New Promotions                                                  **/
///**  Notes:                                                                                         **/
///*****************************************************************************************************/
//	iTemp = GC.getPromotionInfo(ePromotion).isDefensiveVictoryMove();
//	if ((AI_getUnitAIType() == UNITAI_RESERVE) ||
//		  (AI_getUnitAIType() == UNITAI_COUNTER) ||
//			(AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
//			(AI_getUnitAIType() == UNITAI_CITY_COUNTER) ||
//			(AI_getUnitAIType() == UNITAI_CITY_SPECIAL) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK))
//	{
//		iValue += 10;
//	}
//	else
//	{
//		iValue += 8;
//	}
//
//	if (noDefensiveBonus())
//	{
//		iValue *= 100;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isFreeDrop();
//	if ((AI_getUnitAIType() == UNITAI_PILLAGE) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK))
//	{
//		iValue += 10;
//	}
//	else
//	{
//		iValue += 8;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isOffensiveVictoryMove();
//	if ((AI_getUnitAIType() == UNITAI_PILLAGE) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK) ||
//			(AI_getUnitAIType() == UNITAI_PARADROP))
//	{
//		iValue += 10;
//	}
//	else
//	{
//		iValue += 8;
//	}
//
//	if (isBlitz() || isFreeDrop())
//	{
//		iValue *= 20;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isPillageCulture();
//	if (isPillageOnMove() || isPillageOnVictory())
//	{
//		if (AI_getUnitAIType() == UNITAI_PILLAGE)
//		{
//			iValue += 10;
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//				(AI_getUnitAIType() == UNITAI_PARADROP))
//		{
//			iValue += 8;
//		}
//		else
//		{
//			iValue += 4;
//		}
//	}
//	else
//	{
//		iValue += 2;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isPillageEspionage();
//	if (isPillageOnMove() || isPillageOnVictory())
//	{
//		if (AI_getUnitAIType() == UNITAI_PILLAGE)
//		{
//			iValue += 10;
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//				(AI_getUnitAIType() == UNITAI_PARADROP))
//		{
//			iValue += 8;
//		}
//		else
//		{
//			iValue += 4;
//		}
//	}
//	else
//	{
//		iValue += 2;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isPillageMarauder();
//	if (isPillageOnMove() || isPillageOnVictory())
//	{
//		if (AI_getUnitAIType() == UNITAI_PILLAGE)
//		{
//			iValue += 10;
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//				(AI_getUnitAIType() == UNITAI_PARADROP))
//		{
//			iValue += 8;
//		}
//		else
//		{
//			iValue += 4;
//		}
//	}
//	else
//	{
//		iValue += 2;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isPillageOnMove();
//	if ((isPillageCulture()) ||
//		(isPillageEspionage()) ||
//		(isPillageMarauder()) ||
//		(isPillageResearch()))
//	{
//		if ((AI_getUnitAIType() == UNITAI_PILLAGE) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK) ||
//			(AI_getUnitAIType() == UNITAI_PARADROP))
//		{
//			iValue += 10;
//		}
//		else
//		{
//			iValue += 8;
//		}
//	}
//	else
//	{
//		iValue++;
//	}
//
//	if (getMoves() > 1)
//	{
//		iValue *= 100;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isPillageOnVictory();
//	if ((isPillageCulture()) ||
//		(isPillageEspionage()) ||
//		(isPillageMarauder()) ||
//		(isPillageResearch()))
//	{
//		if ((AI_getUnitAIType() == UNITAI_PILLAGE) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK) ||
//			(AI_getUnitAIType() == UNITAI_PARADROP))
//		{
//			iValue += 20;
//		}
//		else
//		{
//			iValue += 12;
//		}
//	}
//	else
//	{
//		iValue += 4;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).isPillageResearch();
//	if (isPillageOnMove() || isPillageOnVictory())
//	{
//		if (AI_getUnitAIType() == UNITAI_PILLAGE)
//		{
//			iValue += 10;
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//				(AI_getUnitAIType() == UNITAI_PARADROP))
//		{
//			iValue += 8;
//		}
//		else
//		{
//			iValue += 4;
//		}
//	}
//	else
//	{
//		iValue += 2;
//	}
//	
//	iTemp = GC.getPromotionInfo(ePromotion).getAirCombatLimitChange();
//	if ((AI_getUnitAIType() == UNITAI_ATTACK_AIR) ||
//		(AI_getUnitAIType() == UNITAI_CARRIER_AIR) ||
//		(AI_getUnitAIType() == UNITAI_DEFENSE_AIR))
//	{
//		iValue += 20;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCelebrityHappy();
//	if ((AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
//		(AI_getUnitAIType() == UNITAI_CITY_COUNTER))
//	{
//		CvCity* pCity = plot()->getPlotCity();
//		if (pCity != NULL)
//		{
//			if ((pCity->happyLevel()) < (pCity->unhappyLevel()))
//			{
//				iValue = (iTemp * 5);
//			}
//			else
//			{
//				iValue = (iTemp / 100);
//			}
//		}
//	}
//	else
//	{
//		iValue /= 100;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCollateralDamageLimitChange();
//	if ((AI_getUnitAIType() == UNITAI_ATTACK_AIR) ||
//		(AI_getUnitAIType() == UNITAI_CARRIER_AIR) ||
//		(AI_getUnitAIType() == UNITAI_DEFENSE_AIR) ||
//		(AI_getUnitAIType() == UNITAI_COLLATERAL))
//	{
//		iValue += 20;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCollateralDamageMaxUnitsChange();
//	if ((AI_getUnitAIType() == UNITAI_ATTACK_AIR) ||
//		(AI_getUnitAIType() == UNITAI_CARRIER_AIR) ||
//		(AI_getUnitAIType() == UNITAI_DEFENSE_AIR) ||
//		(AI_getUnitAIType() == UNITAI_COLLATERAL))
//	{
//		iValue += 20;
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCombatLimitChange();
//	if (AI_getUnitAIType() == UNITAI_COLLATERAL)
//	{
//		iValue += (iTemp * 3);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getExtraDropRange();
//	if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			(AI_getUnitAIType() == UNITAI_PARADROP))
//	{
//		iValue += 20;
//	}
///*****************************************************************************************************/
///**  TheLadiesOgre; 16.09.2009; TLOTags                                                             **/
///*****************************************************************************************************/
//
//	if (GC.getPromotionInfo(ePromotion).isLeader())
//	{
//		// Don't consume the leader as a regular promotion
//		return 0;
//	}
//
//	if (GC.getPromotionInfo(ePromotion).isBlitz())
//	{
//		if ((AI_getUnitAIType() == UNITAI_RESERVE  && baseMoves() > 1) || 
//			AI_getUnitAIType() == UNITAI_PARADROP)
//		{
//			iValue += 10;
//		}
//		else
//		{
//			iValue += 2;
//		}
//	}
//
//	if (GC.getPromotionInfo(ePromotion).isAmphib())
//	{
//		if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			  (AI_getUnitAIType() == UNITAI_ATTACK_CITY))
//		{
//			iValue += 5;
//		}
//		else
//		{
//			iValue++;
//		}
//	}
//
//	if (GC.getPromotionInfo(ePromotion).isRiver())
//	{
//		if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			  (AI_getUnitAIType() == UNITAI_ATTACK_CITY))
//		{
//			iValue += 5;
//		}
//		else
//		{
//			iValue++;
//		}
//	}
//
//	if (GC.getPromotionInfo(ePromotion).isEnemyRoute())
//	{
//		if (AI_getUnitAIType() == UNITAI_PILLAGE)
//		{
//			iValue += 40;
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			       (AI_getUnitAIType() == UNITAI_ATTACK_CITY))
//		{
//			iValue += 20;
//		}
//		else if (AI_getUnitAIType() == UNITAI_PARADROP)
//		{
//			iValue += 10;
//		}
//		else
//		{
//			iValue += 4;
//		}
//	}
//
//	if (GC.getPromotionInfo(ePromotion).isAlwaysHeal())
//	{
//		if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			  (AI_getUnitAIType() == UNITAI_ATTACK_CITY) ||
//				(AI_getUnitAIType() == UNITAI_PILLAGE) ||
//				(AI_getUnitAIType() == UNITAI_COUNTER) ||
//				(AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
//				(AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
//				(AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
//				(AI_getUnitAIType() == UNITAI_PARADROP))
//		{
//			iValue += 10;
//		}
//		else
//		{
//			iValue += 8;
//		}
//	}
//
//	if (GC.getPromotionInfo(ePromotion).isHillsDoubleMove())
//	{
//		if (AI_getUnitAIType() == UNITAI_EXPLORE)
//		{
//			iValue += 20;
//		}
//		else
//		{
//			iValue += 10;
//		}
//	}
//
//	if (GC.getPromotionInfo(ePromotion).isImmuneToFirstStrikes() 
//		&& !immuneToFirstStrikes())
//	{
//		if ((AI_getUnitAIType() == UNITAI_ATTACK_CITY))
//		{
//			iValue += 12;			
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK))
//		{
//			iValue += 8;
//		}
//		else
//		{
//			iValue += 4;
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getVisibilityChange();
//	if ((AI_getUnitAIType() == UNITAI_EXPLORE_SEA) || 
//		(AI_getUnitAIType() == UNITAI_EXPLORE))
//	{
//		iValue += (iTemp * 40);
//	}
//	else if (AI_getUnitAIType() == UNITAI_PIRATE_SEA) 
//	{
//		iValue += (iTemp * 20);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getMovesChange();
//	if ((AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
//		(AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
//		  (AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||
//		  (AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
//			(AI_getUnitAIType() == UNITAI_EXPLORE_SEA) ||
//			(AI_getUnitAIType() == UNITAI_ASSAULT_SEA) ||
//			(AI_getUnitAIType() == UNITAI_SETTLER_SEA) ||
//			(AI_getUnitAIType() == UNITAI_PILLAGE) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK) ||
//			(AI_getUnitAIType() == UNITAI_PARADROP))
//	{
//		iValue += (iTemp * 20);
//	}
//	else
//	{
//		iValue += (iTemp * 4);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getMoveDiscountChange();
//	if (AI_getUnitAIType() == UNITAI_PILLAGE)
//	{
//		iValue += (iTemp * 10);
//	}
//	else
//	{
//		iValue += (iTemp * 2);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getAirRangeChange();
//	if (AI_getUnitAIType() == UNITAI_ATTACK_AIR ||
//		AI_getUnitAIType() == UNITAI_CARRIER_AIR)
//	{
//		iValue += (iTemp * 20);
//	}
//	else if (AI_getUnitAIType() == UNITAI_DEFENSE_AIR)
//	{
//		iValue += (iTemp * 10);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getInterceptChange();
//	if (AI_getUnitAIType() == UNITAI_DEFENSE_AIR)
//	{
//		iValue += (iTemp * 3);
//	}
//	else if (AI_getUnitAIType() == UNITAI_CITY_SPECIAL || AI_getUnitAIType() == UNITAI_CARRIER_AIR)
//	{
//		iValue += (iTemp * 2);
//	}
//	else
//	{
//		iValue += (iTemp / 10);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getEvasionChange();
//	if (AI_getUnitAIType() == UNITAI_ATTACK_AIR || AI_getUnitAIType() == UNITAI_CARRIER_AIR)
//	{
//		iValue += (iTemp * 3);
//	}
//	else
//	{
//		iValue += (iTemp / 10);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getFirstStrikesChange() * 2;
//	iTemp += GC.getPromotionInfo(ePromotion).getChanceFirstStrikesChange();
//	if ((AI_getUnitAIType() == UNITAI_RESERVE) ||
//		  (AI_getUnitAIType() == UNITAI_COUNTER) ||
//			(AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
//			(AI_getUnitAIType() == UNITAI_CITY_COUNTER) ||
//			(AI_getUnitAIType() == UNITAI_CITY_SPECIAL) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK))
//	{
//		iTemp *= 8;
//		iExtra = getExtraChanceFirstStrikes() + getExtraFirstStrikes() * 2;
//		iTemp *= 100 + iExtra * 15;
//		iTemp /= 100;
//		iValue += iTemp;
//	}
//	else
//	{
//		iValue += (iTemp * 5);
//	}
//
//
//	iTemp = GC.getPromotionInfo(ePromotion).getWithdrawalChange();
//	if (iTemp != 0)
//	{
//		iExtra = (m_pUnitInfo->getWithdrawalProbability() + (getExtraWithdrawal() * 4));
//		iTemp *= (100 + iExtra);
//		iTemp /= 100;
//		if ((AI_getUnitAIType() == UNITAI_ATTACK_CITY))
//		{
//			iValue += (iTemp * 4) / 3;
//		}
//		else if ((AI_getUnitAIType() == UNITAI_COLLATERAL) ||
//			  (AI_getUnitAIType() == UNITAI_RESERVE) ||
//			  (AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||
//			  getLeaderUnitType() != NO_UNIT)
//		{
//			iValue += iTemp * 1;
//		}
//		else
//		{
//			iValue += (iTemp / 4);
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCollateralDamageChange();
//	if (iTemp != 0)
//	{
//		iExtra = (getExtraCollateralDamage());//collateral has no strong synergy (not like retreat)
//		iTemp *= (100 + iExtra);
//		iTemp /= 100;
//		
//		if (AI_getUnitAIType() == UNITAI_COLLATERAL)
//		{
//			iValue += (iTemp * 1);
//		}
//		else if (AI_getUnitAIType() == UNITAI_ATTACK_CITY)
//		{
//			iValue += ((iTemp * 2) / 3);
//		}
//		else
//		{
//			iValue += (iTemp / 8);
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getBombardRateChange();
//	if (AI_getUnitAIType() == UNITAI_ATTACK_CITY)
//	{
//		iValue += (iTemp * 2);
//	}
//	else
//	{
//		iValue += (iTemp / 8);
//	}
//
///************************************************************************************************/
///* BETTER_BTS_AI_MOD                      04/26/10                                jdog5000      */
///*                                                                                              */
///* Unit AI                                                                                      */
///************************************************************************************************/
//	iTemp = GC.getPromotionInfo(ePromotion).getEnemyHealChange();	
//	if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//		(AI_getUnitAIType() == UNITAI_PILLAGE) ||
//		(AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
//		(AI_getUnitAIType() == UNITAI_PARADROP) ||
//		(AI_getUnitAIType() == UNITAI_PIRATE_SEA))
///************************************************************************************************/
///* BETTER_BTS_AI_MOD                       END                                                  */
///************************************************************************************************/
//	{
//		iValue += (iTemp / 4);
//	}
//	else
//	{
//		iValue += (iTemp / 8);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getNeutralHealChange();
//	iValue += (iTemp / 8);
//
//	iTemp = GC.getPromotionInfo(ePromotion).getFriendlyHealChange();
//	if ((AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
//		  (AI_getUnitAIType() == UNITAI_CITY_COUNTER) ||
//		  (AI_getUnitAIType() == UNITAI_CITY_SPECIAL))
//	{
//		iValue += (iTemp / 4);
//	}
//	else
//	{
//		iValue += (iTemp / 8);
//	}
//
///************************************************************************************************/
///* BETTER_BTS_AI_MOD                      04/26/10                                jdog5000      */
///*                                                                                              */
///* Unit AI                                                                                      */
///************************************************************************************************/
//    if ( getDamage() > 0 || ((AI_getBirthmark() % 8 == 0) && (AI_getUnitAIType() == UNITAI_COUNTER || 
//															AI_getUnitAIType() == UNITAI_PILLAGE ||
//															AI_getUnitAIType() == UNITAI_ATTACK_CITY ||
//															AI_getUnitAIType() == UNITAI_RESERVE )) )
//    {
///************************************************************************************************/
///* BETTER_BTS_AI_MOD                       END                                                  */
///************************************************************************************************/
//        iTemp = GC.getPromotionInfo(ePromotion).getSameTileHealChange() + getSameTileHeal();
//        iExtra = getSameTileHeal();
//        
//        iTemp *= (100 + iExtra * 5);
//        iTemp /= 100;
//        
//        if (iTemp > 0)
//        {
//            if (healRate(plot()) < iTemp)
//            {
//                iValue += iTemp * ((getGroup()->getNumUnits() > 4) ? 4 : 2);
//            }
//            else
//            {
//                iValue += (iTemp / 8);
//            }
//        }
//
//        iTemp = GC.getPromotionInfo(ePromotion).getAdjacentTileHealChange();
//        iExtra = getAdjacentTileHeal();
//        iTemp *= (100 + iExtra * 5);
//        iTemp /= 100;
//        if (getSameTileHeal() >= iTemp)
//        {
//            iValue += (iTemp * ((getGroup()->getNumUnits() > 9) ? 4 : 2));
//        }
//        else
//        {
//            iValue += (iTemp / 4);
//        }
//    }
//
//	// try to use Warlords to create super-medic units
//	if (GC.getPromotionInfo(ePromotion).getAdjacentTileHealChange() > 0 || GC.getPromotionInfo(ePromotion).getSameTileHealChange() > 0)
//	{
//		PromotionTypes eLeader = NO_PROMOTION;
//		for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
//		{
//			if (GC.getPromotionInfo((PromotionTypes)iI).isLeader())
//			{
//				eLeader = (PromotionTypes)iI;
//			}
//		}
//		
//		if (isHasPromotion(eLeader) && eLeader != NO_PROMOTION)
//		{
//			iValue += GC.getPromotionInfo(ePromotion).getAdjacentTileHealChange() + GC.getPromotionInfo(ePromotion).getSameTileHealChange();
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCombatPercent();
//	if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//		(AI_getUnitAIType() == UNITAI_COUNTER) ||
//		(AI_getUnitAIType() == UNITAI_CITY_COUNTER) ||
//		  (AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
//		  (AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
//			(AI_getUnitAIType() == UNITAI_PARADROP) ||
//			(AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
//			(AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||
//			(AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
//			(AI_getUnitAIType() == UNITAI_CARRIER_SEA) ||
//			(AI_getUnitAIType() == UNITAI_ATTACK_AIR) ||
//			(AI_getUnitAIType() == UNITAI_CARRIER_AIR))
//	{
//		iValue += (iTemp * 2);
//	}
//	else
//	{
//		iValue += (iTemp * 1);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCityAttackPercent();
//	if (iTemp != 0)
//	{
//		if (m_pUnitInfo->getUnitAIType(UNITAI_ATTACK) || m_pUnitInfo->getUnitAIType(UNITAI_ATTACK_CITY) || m_pUnitInfo->getUnitAIType(UNITAI_ATTACK_CITY_LEMMING))
//		{
//			iExtra = (m_pUnitInfo->getCityAttackModifier() + (getExtraCityAttackPercent() * 2));
//			iTemp *= (100 + iExtra);
//			iTemp /= 100;
//			if (AI_getUnitAIType() == UNITAI_ATTACK_CITY)
//			{
//				iValue += (iTemp * 1);
//			}
//			else 
//			{
//				iValue -= iTemp / 4;
//			}
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCityDefensePercent();
//	if (iTemp != 0)
//	{
//		if ((AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
//			  (AI_getUnitAIType() == UNITAI_CITY_SPECIAL))
//		{
//			iExtra = m_pUnitInfo->getCityDefenseModifier() + (getExtraCityDefensePercent() * 2);
//			iValue += ((iTemp * (100 + iExtra)) / 100);
//		}
//		else
//		{
//			iValue += (iTemp / 4);
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getHillsAttackPercent();
//	if (iTemp != 0)
//	{
//		iExtra = getExtraHillsAttackPercent();
//		iTemp *= (100 + iExtra * 2);
//		iTemp /= 100;
//		if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			(AI_getUnitAIType() == UNITAI_COUNTER))
//		{
//			iValue += (iTemp / 4);
//		}
//		else
//		{
//			iValue += (iTemp / 16);
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getHillsDefensePercent();
//	if (iTemp != 0)
//	{
//		iExtra = (m_pUnitInfo->getHillsDefenseModifier() + (getExtraHillsDefensePercent() * 2)); 
//		iTemp *= (100 + iExtra);
//		iTemp /= 100;
//		if (AI_getUnitAIType() == UNITAI_CITY_DEFENSE)
//		{
//			if (plot()->isCity() && plot()->isHills())
//			{
//				iValue += (iTemp * 4) / 3;
//			}
//		}
//		else if (AI_getUnitAIType() == UNITAI_COUNTER)
//		{
//			if (plot()->isHills())
//			{
//				iValue += (iTemp / 4);
//			}
//			else
//			{
//				iValue++;
//			}
//		}
//		else
//		{
//			iValue += (iTemp / 16);
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getRevoltProtection();
//	if ((AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
//		(AI_getUnitAIType() == UNITAI_CITY_COUNTER) ||
//		(AI_getUnitAIType() == UNITAI_CITY_SPECIAL))
//	{
//		if (iTemp > 0)
//		{
//			PlayerTypes eOwner = plot()->calculateCulturalOwner();
//			if (eOwner != NO_PLAYER && GET_PLAYER(eOwner).getTeam() != GET_PLAYER(getOwnerINLINE()).getTeam())
//			{
//				iValue += (iTemp / 2);
//			}
//		}
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getCollateralDamageProtection();
//	if ((AI_getUnitAIType() == UNITAI_CITY_DEFENSE) ||
//		(AI_getUnitAIType() == UNITAI_CITY_COUNTER) ||
//		(AI_getUnitAIType() == UNITAI_CITY_SPECIAL))
//	{
//		iValue += (iTemp / 3);
//	}
//	else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//		(AI_getUnitAIType() == UNITAI_COUNTER))
//	{
//		iValue += (iTemp / 4);
//	}
//	else
//	{
//		iValue += (iTemp / 8);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getPillageChange();
//	if (AI_getUnitAIType() == UNITAI_PILLAGE ||
//		AI_getUnitAIType() == UNITAI_ATTACK_SEA ||
//		AI_getUnitAIType() == UNITAI_PIRATE_SEA)
//	{
//		iValue += (iTemp / 4);
//	}
//	else
//	{
//		iValue += (iTemp / 16);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getUpgradeDiscount();
//	iValue += (iTemp / 16);
//
//	iTemp = GC.getPromotionInfo(ePromotion).getExperiencePercent();
//	if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//		(AI_getUnitAIType() == UNITAI_ATTACK_SEA) ||
//		(AI_getUnitAIType() == UNITAI_PIRATE_SEA) ||
//		(AI_getUnitAIType() == UNITAI_RESERVE_SEA) ||
//		(AI_getUnitAIType() == UNITAI_ESCORT_SEA) ||
//		(AI_getUnitAIType() == UNITAI_CARRIER_SEA) ||
//		(AI_getUnitAIType() == UNITAI_MISSILE_CARRIER_SEA))
//	{
//		iValue += (iTemp * 1);
//	}
//	else
//	{
//		iValue += (iTemp / 2);
//	}
//
//	iTemp = GC.getPromotionInfo(ePromotion).getKamikazePercent();
//	if (AI_getUnitAIType() == UNITAI_ATTACK_CITY)
//	{
//		iValue += (iTemp / 16);
//	}
//	else
//	{
//		iValue += (iTemp / 64);
//	}
//
//	for (iI = 0; iI < GC.getNumTerrainInfos(); iI++)
//	{
//		iTemp = GC.getPromotionInfo(ePromotion).getTerrainAttackPercent(iI);
//		if (iTemp != 0)
//		{
//			iExtra = getExtraTerrainAttackPercent((TerrainTypes)iI);
//			iTemp *= (100 + iExtra * 2);
//			iTemp /= 100;
//			if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//				(AI_getUnitAIType() == UNITAI_COUNTER))
//			{
//				iValue += (iTemp / 4);
//			}
//			else
//			{
//				iValue += (iTemp / 16);
//			}
//		}
//
//		iTemp = GC.getPromotionInfo(ePromotion).getTerrainDefensePercent(iI);
//		if (iTemp != 0)
//		{
//			iExtra =  getExtraTerrainDefensePercent((TerrainTypes)iI);
//			iTemp *= (100 + iExtra);
//			iTemp /= 100;
//			if (AI_getUnitAIType() == UNITAI_COUNTER)
//			{
//				if (plot()->getTerrainType() == (TerrainTypes)iI)
//				{
//					iValue += (iTemp / 4);
//				}
//				else
//				{
//					iValue++;
//				}
//			}
//			else
//			{
//				iValue += (iTemp / 16);
//			}
//		}
//
//		if (GC.getPromotionInfo(ePromotion).getTerrainDoubleMove(iI))
//		{
//			if (AI_getUnitAIType() == UNITAI_EXPLORE)
//			{
//				iValue += 20;
//			}
//			else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_PILLAGE))
//			{
//				iValue += 10;
//			}
//			else
//			{
//			    iValue += 1;
//			}
//		}
//	}
//
//	for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
//	{
//		iTemp = GC.getPromotionInfo(ePromotion).getFeatureAttackPercent(iI);
//		if (iTemp != 0)
//		{
//			iExtra = getExtraFeatureAttackPercent((FeatureTypes)iI);
//			iTemp *= (100 + iExtra * 2);
//			iTemp /= 100;
//			if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//				(AI_getUnitAIType() == UNITAI_COUNTER))
//			{
//				iValue += (iTemp / 4);
//			}
//			else
//			{
//				iValue += (iTemp / 16);
//			}
//		}
//
//		iTemp = GC.getPromotionInfo(ePromotion).getFeatureDefensePercent(iI);
//		if (iTemp != 0)
//		{
//			iExtra = getExtraFeatureDefensePercent((FeatureTypes)iI);
//			iTemp *= (100 + iExtra * 2);
//			iTemp /= 100;
//			
//			if (!noDefensiveBonus())
//			{
//				if (AI_getUnitAIType() == UNITAI_COUNTER)
//				{
//					if (plot()->getFeatureType() == (FeatureTypes)iI)
//					{
//						iValue += (iTemp / 4);
//					}
//					else
//					{
//						iValue++;
//					}
//				}
//				else
//				{
//					iValue += (iTemp / 16);
//				}
//			}
//		}
//
//		if (GC.getPromotionInfo(ePromotion).getFeatureDoubleMove(iI))
//		{
//			if (AI_getUnitAIType() == UNITAI_EXPLORE)
//			{
//				iValue += 20;
//			}
//			else if ((AI_getUnitAIType() == UNITAI_ATTACK) || (AI_getUnitAIType() == UNITAI_PILLAGE))
//			{
//				iValue += 10;
//			}
//			else
//			{
//			    iValue += 1;
//			}
//		}
//	}
//
//    int iOtherCombat = 0; 
//    int iSameCombat = 0;
//    
//    for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
//    {
//        if ((UnitCombatTypes)iI == getUnitCombatType())
//        {
//            iSameCombat += unitCombatModifier((UnitCombatTypes)iI);
//        }
//        else
//        {
//            iOtherCombat += unitCombatModifier((UnitCombatTypes)iI);
//        }
//    }
//
//	for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
//	{
//		iTemp = GC.getPromotionInfo(ePromotion).getUnitCombatModifierPercent(iI);
//		int iCombatWeight = 0;
//        //Fighting their own kind
//        if ((UnitCombatTypes)iI == getUnitCombatType())
//        {
//            if (iSameCombat >= iOtherCombat)
//            {
//                iCombatWeight = 70;//"axeman takes formation"
//            }
//            else
//            {
//                iCombatWeight = 30;
//            }
//        }
//        else
//        {
//            //fighting other kinds
//            if (unitCombatModifier((UnitCombatTypes)iI) > 10)
//            {
//                iCombatWeight = 70;//"spearman takes formation"
//            }
//            else
//            {
//                iCombatWeight = 30;
//            }
//        }
//
//		iCombatWeight *= GET_PLAYER(getOwnerINLINE()).AI_getUnitCombatWeight((UnitCombatTypes)iI);
//		iCombatWeight /= 100;		
//		
//		if ((AI_getUnitAIType() == UNITAI_COUNTER) || (AI_getUnitAIType() == UNITAI_CITY_COUNTER))
//		{
//		    iValue += (iTemp * iCombatWeight) / 50;
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			       (AI_getUnitAIType() == UNITAI_RESERVE))
//		{
//			iValue += (iTemp * iCombatWeight) / 100;
//		}
//		else
//		{
//			iValue += (iTemp * iCombatWeight) / 200;
//		}
//	}
//
//	for (iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
//	{
//		//WTF? why float and cast to int?
//		//iTemp = ((int)((GC.getPromotionInfo(ePromotion).getDomainModifierPercent(iI) + getExtraDomainModifier((DomainTypes)iI)) * 100.0f));
//		iTemp = GC.getPromotionInfo(ePromotion).getDomainModifierPercent(iI);
//		if (AI_getUnitAIType() == UNITAI_COUNTER)
//		{
//			iValue += (iTemp * 1);
//		}
//		else if ((AI_getUnitAIType() == UNITAI_ATTACK) ||
//			       (AI_getUnitAIType() == UNITAI_RESERVE))
//		{
//			iValue += (iTemp / 2);
//		}
//		else
//		{
//			iValue += (iTemp / 8);
//		}
//	}
//
//	if (iValue > 0)
//	{
//		iValue += GC.getGameINLINE().getSorenRandNum(15, "AI Promote");
//	}
//
//	return iValue;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_shadow(UnitAITypes eUnitAI, int iMax, int iMaxRatio, bool bWithCargoOnly, bool bOutsideCityOnly, int iMaxPath)
{
	PROFILE_FUNC();

	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;

	iBestValue = 0;
	pBestUnit = NULL;

	DomainTypes domain = getDomainType();

	for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
	{
		if (pLoopUnit != this)
		{
			if (pLoopUnit->getDomainType() == domain && pLoopUnit->isGroupHead())
			{
				if (!(pLoopUnit->isCargo()))
				{
					if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
					{
						if (AI_plotValid(pLoopUnit->plot()))
						{
							if (pLoopUnit->getGroup()->baseMoves() <= getGroup()->baseMoves())
							{
								if (!bWithCargoOnly || pLoopUnit->getGroup()->hasCargo())
								{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      12/08/08                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
									if( bOutsideCityOnly && pLoopUnit->plot()->isCity() )
									{
										continue;
									}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

									int iShadowerCount = GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_SHADOW, getGroup());
									if (((-1 == iMax) || (iShadowerCount < iMax)) &&
										 ((-1 == iMaxRatio) || (iShadowerCount == 0) || (((100 * iShadowerCount) / std::max(1, pLoopUnit->getGroup()->countNumUnitAIType(eUnitAI))) <= iMaxRatio)))
									{
										if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
										{
											if (generatePath(pLoopUnit->plot(), 0, true, &iPathTurns))
											{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      12/08/08                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
												//if (iPathTurns <= iMaxPath) XXX
*/
												if (iPathTurns <= iMaxPath)
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
												{
													iValue = 1 + pLoopUnit->getGroup()->getCargo();
													iValue *= 1000;
													iValue /= 1 + iPathTurns;

													if (iValue > iBestValue)
													{
														iBestValue = iValue;
														pBestUnit = pLoopUnit;
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestUnit != NULL)
	{
		if (atPlot(pBestUnit->plot()))
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_SHADOW, NULL, pBestUnit);
			return true;
		}
		else
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_SHADOW, NULL, pBestUnit);
		}
	}

	return false;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/22/10                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
// Added new options to aid transport grouping
// Returns true if a group was joined or a mission was pushed...
bool CvUnitAI::AI_group(UnitAITypes eUnitAI, int iMaxGroup, int iMaxOwnUnitAI, int iMinUnitAI, bool bIgnoreFaster, bool bIgnoreOwnUnitType, bool bStackOfDoom, int iMaxPath, bool bAllowRegrouping, bool bWithCargoOnly, bool bInCityOnly, MissionAITypes eIgnoreMissionAIType, AutomateTypes eAutomateType)
{
	PROFILE_FUNC();

	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	bool bCanDefend = getGroup()->canDefend();

	// if we are on a transport, then do not regroup
	if (isCargo())
	{
		return false;
	}

	if (!bAllowRegrouping)
	{
		if (getGroup()->getNumUnits() > 1)
		{
			return false;
		}
	}
	
	if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
	{
		if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
		{
			return false;
		}
	}

	if (!AI_canGroupWithAIType(eUnitAI))
	{
		return false;
	}

	if ( GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(eUnitAI) == 0 )
	{
		return false;
	}

	int iOurImpassableCount = 0;
	CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
	while (pUnitNode != NULL)
	{
		CvUnit* pImpassUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = getGroup()->nextUnitNode(pUnitNode);

		iOurImpassableCount = std::max(iOurImpassableCount, GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(pImpassUnit->getUnitType()));
	}

	iBestValue = MAX_INT;
	pBestUnit = NULL;

	CvReachablePlotSet plotSet(getGroup(), bCanDefend ? 0 : MOVE_OUR_TERRITORY, AI_searchRange(iMaxPath));

	// Loop over groups, ai_allowgroup blocks non-head units anyway
	CvSelectionGroup* pLoopGroup = NULL;
	for(pLoopGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
	{
		pLoopUnit = pLoopGroup->getHeadUnit();
		if( pLoopUnit == NULL )
		{
			continue;
		}

		if (eAutomateType != NO_AUTOMATE && pLoopUnit->getGroup()->getAutomateType() != eAutomateType)
		{
			continue;
		}

		CvPlot* pPlot = pLoopUnit->plot();
		if (/*AI_plotValid(pPlot) &&*/ plotSet.find(pPlot) != plotSet.end())
		{
			if (iMaxPath > 0 || pPlot == plot())
			{
				if (!isEnemy(pPlot->getTeam()))
				{
					if (AI_allowGroup(pLoopUnit, eUnitAI))
					{
						if ((iMaxGroup == -1) || ((pLoopGroup->getNumUnits() + GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, MISSIONAI_GROUP, getGroup())) <= (iMaxGroup + ((bStackOfDoom) ? AI_stackOfDoomExtra() : 0))))
						{
							if ((iMaxOwnUnitAI == -1) || (pLoopGroup->countNumUnitAIType(AI_getUnitAIType()) <= (iMaxOwnUnitAI + ((bStackOfDoom) ? AI_stackOfDoomExtra() : 0))))
							{
								if ((iMinUnitAI == -1) || (pLoopGroup->countNumUnitAIType(eUnitAI) >= iMinUnitAI))
								{
									if (!bIgnoreFaster || (pLoopGroup->baseMoves() <= baseMoves()))
									{
										if (!bIgnoreOwnUnitType || (pLoopUnit->getUnitType() != getUnitType()))
										{
											if (!bWithCargoOnly || pLoopUnit->getGroup()->hasCargo())
											{
												if( !bInCityOnly || pLoopUnit->plot()->isCity() )
												{
													if( (eIgnoreMissionAIType == NO_MISSIONAI) || (eIgnoreMissionAIType != pLoopUnit->getGroup()->AI_getMissionAIType()) )
													{
														if (!(pPlot->isVisibleEnemyUnit(this)))
														{
															if( iOurImpassableCount > 0 || AI_getUnitAIType() == UNITAI_ASSAULT_SEA )
															{
																int iTheirImpassableCount = 0;
																pUnitNode = pLoopGroup->headUnitNode();
																while (pUnitNode != NULL)
																{
																	CvUnit* pImpassUnit = ::getUnit(pUnitNode->m_data);
																	pUnitNode = pLoopGroup->nextUnitNode(pUnitNode);

																	iTheirImpassableCount = std::max(iTheirImpassableCount, GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(pImpassUnit->getUnitType()));
																}

																if( iOurImpassableCount != iTheirImpassableCount )
																{
																	continue;
																}
															}

															if (generatePath(pPlot, bCanDefend ? 0 : MOVE_OUR_TERRITORY, true, &iPathTurns))
															{
																if (iPathTurns <= iMaxPath)
																{
																	iValue = 1000 * (iPathTurns + 1);
																	iValue *= 4 + pLoopGroup->getCargo();
																	iValue /= pLoopGroup->getNumUnits();

																	if (iValue < iBestValue)
																	{
																		iBestValue = iValue;
																		pBestUnit = pLoopUnit;
																	}
																}
															}
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	
	if (pBestUnit != NULL)
	{
		if (atPlot(pBestUnit->plot()))
		{
			joinGroup(pBestUnit->getGroup());
			return true;
		}
		else
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), bCanDefend ? 0 : (MOVE_RECONSIDER_ON_LEAVING_OWNED | MOVE_OUR_TERRITORY | MOVE_WITH_CAUTION), false, false, MISSIONAI_GROUP, NULL, pBestUnit);
		}
	}

	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
bool CvUnitAI::AI_groupMergeRange(UnitAITypes eUnitAI, int iMaxRange, bool bBiggerOnly, bool bAllowRegrouping, bool bIgnoreFaster)
{
	PROFILE_FUNC();


 	// if we are on a transport, then do not regroup
	if (isCargo())
	{
		return false;
	}

    if (!bAllowRegrouping)
	{
		if (getGroup()->getNumUnits() > 1)
		{
			return false;
		}
	}
	
	if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
	{
		if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
		{
			return false;
		}
	}
	
	if (!AI_canGroupWithAIType(eUnitAI))
	{
		return false;
	}
	
	// cached values
	CvPlot* pPlot = plot();
	CvSelectionGroup* pGroup = getGroup();
	
	// best match
	CvUnit* pBestUnit = NULL;
	int iBestValue = MAX_INT;
	// iterate over plots at each range
	for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
	{
		for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
		{
			CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
			
			if (pLoopPlot != NULL && pLoopPlot->getArea() == pPlot->getArea() && AI_plotValid(pLoopPlot))
			{
				CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
				while (pUnitNode != NULL)
				{
					CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
					pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
					
					CvSelectionGroup* pLoopGroup = pLoopUnit->getGroup();

					if (AI_allowGroup(pLoopUnit, eUnitAI))
					{
						if (bIgnoreFaster || (pLoopUnit->getGroup()->baseMoves() <= baseMoves()))
						{
							if (!bBiggerOnly || (pLoopGroup->getNumUnits() > pGroup->getNumUnits()))
							{
								int iPathTurns;
								if (generatePath(pLoopPlot, 0, true, &iPathTurns, iMaxRange+2))
								{
									if (iPathTurns <= (iMaxRange + 2))
									{
										int iValue = 1000 * (iPathTurns + 1);
										iValue /= pLoopGroup->getNumUnits();

										if (iValue < iBestValue)
										{
											iBestValue = iValue;
											pBestUnit = pLoopUnit;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestUnit != NULL)
	{
		if (atPlot(pBestUnit->plot()))
		{
			pGroup->mergeIntoGroup(pBestUnit->getGroup()); 
			return true;
		}
		else
		{
			return pGroup->pushMissionInternal(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), 0, false, false, MISSIONAI_GROUP, NULL, pBestUnit);
		}
	}

	return false;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/18/10                                jdog5000      */
/*                                                                                              */
/* War tactics AI, Unit AI                                                                      */
/************************************************************************************************/
// Returns true if we loaded onto a transport or a mission was pushed...
bool CvUnitAI::AI_load(UnitAITypes eUnitAI, MissionAITypes eMissionAI, UnitAITypes eTransportedUnitAI, int iMinCargo, int iMinCargoSpace, int iMaxCargoSpace, int iMaxCargoOurUnitAI, int iFlags, int iMaxPath, int iMaxTransportPath)
{
	PROFILE_FUNC();

	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;

	if (getCargo() > 0)
	{
		return false;
	}

	if (isCargo())
	{
		getGroup()->pushMission(MISSION_SKIP);
		return true;
	}
	
	if ((getDomainType() == DOMAIN_LAND) && !canMoveAllTerrain())
	{
		if (area()->getNumAIUnits(getOwnerINLINE(), eUnitAI) == 0)
		{
			return false;
		}
	}	

	iBestValue = MAX_INT;
	pBestUnit = NULL;
	
	const int iLoadMissionAICount = 4;
	MissionAITypes aeLoadMissionAI[iLoadMissionAICount] = {MISSIONAI_LOAD_ASSAULT, MISSIONAI_LOAD_SETTLER, MISSIONAI_LOAD_SPECIAL, MISSIONAI_ATTACK_SPY};

	int iCurrentGroupSize = getGroup()->getNumUnits();
		
	{
		PROFILE("CvUnitAI::AI_load.SearchTransport");

		CvReachablePlotSet plotSet(getGroup(), iFlags, iMaxPath);

		for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
		{
			if (pLoopUnit != this)
			{
				if (plotSet.find(pLoopUnit->plot()) != plotSet.end())
				{
					if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
					{
						// special case ASSAULT_SEA UnitAI, so that, if a unit is marked escort, but can load units, it will load them
						// transport units might have been built as escort, this most commonly happens with galleons
						UnitAITypes eLoopUnitAI = pLoopUnit->AI_getUnitAIType();
						if (eLoopUnitAI == eUnitAI)// || (eUnitAI == UNITAI_ASSAULT_SEA && eLoopUnitAI == UNITAI_ESCORT_SEA))
						{
						// Thomas SG - AC: Advanced Cargo START
							int iCargoSpaceAvailable = pLoopUnit->cargoSpaceAvailable(NO_SPECIALUNIT, getDomainType());
							{ 
								for (int iK = 0;iK < getNumSpecialUnitTypes();iK++)
								{ 
									iCargoSpaceAvailable = std::max(iCargoSpaceAvailable,pLoopUnit->cargoSpaceAvailable(getSpecialUnitType(iK), getDomainType()));
								}
							}
						// Thomas SG - AC: Advanced Cargo END						
							iCargoSpaceAvailable -= GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pLoopUnit, aeLoadMissionAI, iLoadMissionAICount, getGroup());
							if (iCargoSpaceAvailable > 0)
							{
								if ((eTransportedUnitAI == NO_UNITAI) || (pLoopUnit->getUnitAICargo(eTransportedUnitAI) > 0))
								{
									if ((iMinCargo == -1) || (pLoopUnit->getCargo() >= iMinCargo))
									{
										// Use existing count of cargo space available
										if ((iMinCargoSpace == -1) || (iCargoSpaceAvailable >= iMinCargoSpace))
										{
											if ((iMaxCargoSpace == -1) || (iCargoSpaceAvailable <= iMaxCargoSpace))
											{
												if ((iMaxCargoOurUnitAI == -1) || (pLoopUnit->getUnitAICargo(AI_getUnitAIType()) <= iMaxCargoOurUnitAI))
												{
													// Don't block city defense from getting on board
													if (true)
													{
														if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
														{
															CvPlot* pUnitTargetPlot = pLoopUnit->getGroup()->AI_getMissionAIPlot();
															if ((pUnitTargetPlot == NULL) || (pUnitTargetPlot->getTeam() == getTeam()) || (!pUnitTargetPlot->isOwned() || !isPotentialEnemy(pUnitTargetPlot->getTeam(), pUnitTargetPlot)))
															{
																iPathTurns = 0;
																if (atPlot(pLoopUnit->plot()) || generatePath(pLoopUnit->plot(), iFlags, true, &iPathTurns, iMaxPath))
																{
																	// prefer a transport that can hold as much of our group as possible 
																	iValue = (std::max(0, iCurrentGroupSize - iCargoSpaceAvailable) * 5) + iPathTurns;

																	if (iValue < iBestValue)
																	{
																		iBestValue = iValue;
																		pBestUnit = pLoopUnit;
																	}
																}
															}
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if( pBestUnit != NULL && iMaxTransportPath < MAX_INT )
	{
		PROFILE("CvUnitAI::AI_load.SearchTarget");

		// Can transport reach enemy in requested time
		bool bFoundEnemyPlotInRange = false;
		int iPathTurns;
		int iRange = iMaxTransportPath * pBestUnit->baseMoves();
		CvPlot* pAdjacentPlot = NULL;

		for( int iDX = -iRange; (iDX <= iRange && !bFoundEnemyPlotInRange); iDX++ )
		{
			for( int iDY = -iRange; (iDY <= iRange && !bFoundEnemyPlotInRange); iDY++ )
			{
				CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

				if( pLoopPlot != NULL )
				{
					if( pLoopPlot->isCoastalLand() )
					{
						if( pLoopPlot->isOwned() )
						{
							if( isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot) && !isBarbarian() )
							{
								if( pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE()) > 0 )
								{
									// Transport cannot enter land plot without cargo, so generate path only works properly if
									// land units are already loaded
									
									for( int iI = 0; (iI < NUM_DIRECTION_TYPES && !bFoundEnemyPlotInRange); iI++ )
									{
										pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), (DirectionTypes)iI);
										if (pAdjacentPlot != NULL)
										{
											if( pAdjacentPlot->isWater() )
											{
												if( pBestUnit->generatePath(pAdjacentPlot, 0, true, &iPathTurns, iMaxTransportPath+1) )
												{
													if (pBestUnit->getPathMovementRemaining() == 0)
													{
														iPathTurns++;
													}

													if( iPathTurns <= iMaxTransportPath )
													{
														bFoundEnemyPlotInRange = true;
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}

		if( !bFoundEnemyPlotInRange )
		{
			pBestUnit = NULL;
		}
	}

	if (pBestUnit != NULL)
	{
		if (atPlot(pBestUnit->plot()))
		{
			CvSelectionGroup* pOtherGroup = NULL;
			getGroup()->setTransportUnit(pBestUnit, &pOtherGroup); // XXX is this dangerous (not pushing a mission...) XXX air units?

			// If part of large group loaded, then try to keep loading the rest
			if( eUnitAI == UNITAI_ASSAULT_SEA && eMissionAI == MISSIONAI_LOAD_ASSAULT )
			{
				if( pOtherGroup != NULL && pOtherGroup->getNumUnits() > 0 )
				{
					if( pOtherGroup->getHeadUnitAI() == AI_getUnitAIType() )
					{
						pOtherGroup->getHeadUnit()->AI_load( eUnitAI, eMissionAI, eTransportedUnitAI, iMinCargo, iMinCargoSpace, iMaxCargoSpace, iMaxCargoOurUnitAI, iFlags, 0, iMaxTransportPath );
					}
					else if( eTransportedUnitAI == NO_UNITAI && iMinCargo < 0 && iMinCargoSpace < 0 && iMaxCargoSpace < 0 && iMaxCargoOurUnitAI < 0 )
					{
						pOtherGroup->getHeadUnit()->AI_load( eUnitAI, eMissionAI, NO_UNITAI, -1, -1, -1, -1, iFlags, 0, iMaxTransportPath );
					}
				}
			}

			return true;
		}
		else
		{
			// BBAI TODO: To split or not to split?
// Thomas SG - AC: Advanced Cargo START
			int iCargoSpaceAvailable = pBestUnit->cargoSpaceAvailable(NO_SPECIALUNIT, getDomainType());
			{				
				for (int iK = 0;iK < getNumSpecialUnitTypes();iK++)
				{ 
					iCargoSpaceAvailable = std::max(iCargoSpaceAvailable,pBestUnit->cargoSpaceAvailable(getSpecialUnitType(iK), getDomainType()));
				}
			}
// Thomas SG - AC: Advanced Cargo END			
			FAssertMsg(iCargoSpaceAvailable > 0, "best unit has no space");

			// split our group to fit on the transport
			CvSelectionGroup* pOtherGroup = NULL;
			CvSelectionGroup* pSplitGroup = getGroup()->splitGroup(iCargoSpaceAvailable, this, &pOtherGroup);			
			FAssertMsg(pSplitGroup != NULL, "splitGroup failed");
			FAssertMsg(m_iGroupID == pSplitGroup->getID(), "splitGroup failed to put unit in the new group");

			if (pSplitGroup != NULL)
			{
				CvPlot* pOldPlot = pSplitGroup->plot();
				pSplitGroup->pushMission(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), iFlags, false, false, eMissionAI, NULL, pBestUnit);
				bool bMoved = (pSplitGroup->plot() != pOldPlot);
				if (!bMoved && pOtherGroup != NULL)
				{
					joinGroup(pOtherGroup);
				}
				return bMoved;
			}
		}
	}

	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


// Returns true if a mission was pushed...
bool CvUnitAI::AI_guardCityBestDefender()
{
	CvCity* pCity;
	CvPlot* pPlot;

	pPlot = plot();
	pCity = pPlot->getPlotCity();

	if (pCity != NULL)
	{
		if (pCity->getOwnerINLINE() == getOwnerINLINE())
		{
			if (pPlot->getBestDefender(getOwnerINLINE()) == this)
			{
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
				getGroup()->AI_setAsGarrison(pCity);
				return true;
			}
		}
	}

	return false;
}

bool CvUnitAI::AI_guardCityMinDefender(bool bSearch)
{
	PROFILE_FUNC();
	
	CvCity* pPlotCity = plot()->getPlotCity();
	if ((pPlotCity != NULL) && (pPlotCity->getOwnerINLINE() == getOwnerINLINE()))
	{
		int iCityDefenderCount = pPlotCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
		if ((iCityDefenderCount - 1) < pPlotCity->AI_minDefenders())
		{
			if ((iCityDefenderCount <= 2) || (GC.getGame().getSorenRandNum(5, "AI shuffle defender") != 0))
			{
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
				getGroup()->AI_setAsGarrison(pPlotCity);
				return true;
			}
		}
	}
	
	if (bSearch)
	{
		int iBestValue = 0;
		CvPlot* pBestPlot = NULL;
		CvPlot* pBestGuardPlot = NULL;
		
		CvCity* pLoopCity;
		int iLoop;

		int iCurrentTurn = GC.getGame().getGameTurn();
		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
			if (AI_plotValid(pLoopCity->plot()))
			{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
				// BBAI efficiency: check area for land units
				if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
				{
					continue;
				}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

				//	Koshling - efficiency in handling babarins who have cities scattered all over
				//	the world - just search nearby ones
				if ( isBarbarian() && stepDistance(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), getX_INLINE(), getY_INLINE()) > 10 )
				{
					continue;
				}

				int iDefendersHave = pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
				int iDefendersNeed = pLoopCity->AI_minDefenders();
				if (iDefendersHave < iDefendersNeed)
				{
					if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
					{
						iDefendersHave += GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_CITY, getGroup());
						if (iDefendersHave < iDefendersNeed + 1)
						{
							int iPathTurns;
							if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
							{
								if (iPathTurns <= 10)
								{
									int iValue = (iDefendersNeed - iDefendersHave) * 20;
									iValue += 2 * std::min(15, iCurrentTurn - pLoopCity->getGameTurnAcquired());
									if (pLoopCity->isOccupation())
									{
										iValue += 5;
									}
									iValue -= iPathTurns;

									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
										pBestGuardPlot = pLoopCity->plot();
									}
								}
							}
						}
					}
				}
			}
		}
		if (pBestPlot != NULL)
		{
			if (atPlot(pBestGuardPlot))
			{
				FAssert(pBestGuardPlot == pBestPlot);
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
				return true;
			}
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
		}
	}
	
	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_guardCity(bool bLeave, bool bSearch, int iMaxPath)
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pLoopCity;
	CvPlot* pPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestGuardPlot;
	bool bDefend;
	int iExtra;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;

	FAssert(getDomainType() == DOMAIN_LAND || getDomainType() == DOMAIN_IMMOBILE);
	
	if ( !getGroup()->canDefend() )
	{
		return false;
	}

	CvReachablePlotSet plotSet(getGroup(), 0, 2);

	//	If we're already close to a city we may be considered part of it's defensive posture - check for those cases
	//	first
	for(int iPlotIndex = 0; iPlotIndex < NUM_CITY_PLOTS_2; iPlotIndex++)
	{
		pPlot = plotCity(plot()->getX_INLINE(),plot()->getY_INLINE(),iPlotIndex);

		if (pPlot != NULL && pPlot->getOwnerINLINE() == getOwnerINLINE())
		{
			pCity = pPlot->getPlotCity();

			if (pCity != NULL && plotSet.find(pPlot) != plotSet.end())
			{
				//	Check property control attributes first - they may cause us to defend in the city
				//	regardless of other conditions
				if ( getGroup()->AI_hasBeneficialPropertyEffectForCity(pCity) )
				{
					//	We have at least one unit that can help the ciy's property control (aka crime usually)
					//	Split ou he best such unit and have it defend in the city
					CvSelectionGroup* pOldGroup = getGroup();
					CvUnit* pEjectedUnit = getGroup()->AI_ejectBestPropertyManipulator(pCity);
					
					FAssert(pEjectedUnit != NULL);
					pEjectedUnit->AI_setUnitAIType(UNITAI_CITY_DEFENSE);

					if ( atPlot(pCity->plot()) )
					{
						//	Mark the ejected unit as part of the city garrison
						pEjectedUnit->getGroup()->AI_setAsGarrison(pCity);
						pEjectedUnit->getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
						return (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this);
					}
					else if ( pEjectedUnit->generatePath(pCity->plot(), 0, true) )
					{
						//	Mark the ejected unit as part of the city garrison
						pEjectedUnit->getGroup()->AI_setAsGarrison(pCity);
						pEjectedUnit->getGroup()->pushMission(MISSION_MOVE_TO, pCity->getX_INLINE(), pCity->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
						return (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this);
					}
					else
					{
						//	If we can't move after all regroup and continue regular defensive processing
						pEjectedUnit->joinGroup(pOldGroup);
					}
				}

				int iPlotDanger2 = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pPlot, 2);

				if (!(pCity->AI_isDanger()))
				{
					iExtra = 0;
				}
				else
				{
					iExtra = -iPlotDanger2;
				}
#if 0
				//	If THIS unit is not a city type, then count non-city types generally when evaluating defense
				//	or else any number of them will still keep them all locked up thinking more defense is needed
				if ( !AI_isCityAIType() )
				{
					int iPlotAllStrength = plot()->plotStrength(UNITVALUE_FLAGS_DEFENSIVE, PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, NULL, -1, -1, 2);
					int iPlotCityAIStrength = plot()->plotStrength(UNITVALUE_FLAGS_DEFENSIVE, PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType, -1, -1, 2);
					
					iExtra += (iPlotAllStrength - iPlotCityAIStrength);
				}
#endif
				bDefend = false;

				//	Never remove the last unit
				if (atPlot(pPlot) && canDefend() && pPlot->plotCount(PUF_canDefend /*PUF_canDefendGroupHead*/, -1, -1, getOwnerINLINE()) == getGroup()->getNumUnits()) // XXX check for other team's units?
				{
					bDefend = true;
				}
				//	Check if it is adequately defended (allowing for this group leaving if it is thinking of doing so)
				//	and also that we don't need the units to maintain happiness
				else if (!(pCity->AI_isDefended(((!canDefend() || !AI_isCityGarrison(pCity)) ? 0 : -getGroup()->AI_getGenericValueTimes100(UNITVALUE_FLAGS_DEFENSIVE)/100) + iExtra)) ||
						 (atPlot(pPlot) && isMilitaryHappiness() && !(pCity->AI_isAdequateHappinessMilitary(-getGroup()->getNumUnits()))))
				{
					bDefend = true;
				}
				else
				{
					//	We have enough units here even if we leave

					//	If we were asking to, leave just allow it
					if ( !bLeave )
					{
						//	Otherwise leave the cityAI types defending and others can do what they wish
						if (AI_isCityAIType())
						{
							bDefend = true;
						}
					}
				}

				if (bDefend)
				{
					//	Need to defend city vicinity but not necessarily the city itself
					bool bGuardInCity = !pCity->AI_isAdequateHappinessMilitary(-1);

					if (!bGuardInCity && canDefend())
					{
						//	Always leave at least half the defense actually in the city, and if there is
						//	danger around keep more (to match the enemy count)
						int currentAllDefenders = pPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, NULL, -1, -1, 2);
						int currentAllCityAIDefenders = pPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType, -1, -1, 2);
						int currentInCityDefenders = pPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM);
						int requiredInCityDefenders = std::max(iPlotDanger2, currentAllDefenders/2);

						if ( currentInCityDefenders <= (requiredInCityDefenders + (atPlot(pPlot) ? getGroup()->getNumUnits() : 0)))
						{
							//	Recall city AI types preferentially if there are enough
							if ( currentAllCityAIDefenders < requiredInCityDefenders || AI_isCityAIType() )
							{
								bGuardInCity = true;
							}
						}
					}

					CvPlot* pBestPlot = NULL;
					CvPlot* pBestGuardPlot = NULL;

					//	If we don't have to guard in the city figure out the best spot
					if ( !bGuardInCity )
					{
						//	Guard a good spot outside the city but in its vicinity
						int iBestValue = 0;

						for(int iI = 0; iI < NUM_CITY_PLOTS_2; iI++)
						{
							CvPlot* pLoopPlot = plotCity(pPlot->getX_INLINE(),pPlot->getY_INLINE(),iI);

							if (pLoopPlot != NULL && AI_plotValid(pLoopPlot) && pLoopPlot->area() == area())
							{
								if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE() &&
									pLoopPlot->getNumVisibleEnemyUnits(getOwnerINLINE()) == 0)
								{
									//	Good defensive sites are way better
									iValue = pLoopPlot->defenseModifier(getTeam(),false);

									//	Boost plots where there is known danger
									iValue = (iValue*(100+pLoopPlot->getDangerCount(getTeam())))/100;
									
									// ls612: If the terrain is damaging, don't guard there
									bool	bHasTerrainDamage = (pLoopPlot->getTerrainTurnDamage(getGroup()) > 0);	
									if (bHasTerrainDamage)
									{
										iValue = 0;
									}

									//	The city itself is considered only as a poor option since we already
									//	decided it wasn't really necessary to defend there in principal
									if (pLoopPlot == pPlot)
									{
										iValue += 2;	//	Make sure this is at least considered minimally viable

										//	Can guard in the city itself if no better candidates found, but down-grade it
										//	by a factor of 2
										iValue /= 2;
									}
									else
									{
										//	If there are already units guarding here reduce the value of another guard
										int iAlreadyGuarding = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_CITY, getGroup(), 0);
										if ( iAlreadyGuarding > 0 )
										{
											iValue /= (iAlreadyGuarding+1);
										}
									}

									if (iValue*1000/3 > iBestValue)
									{
										if (generatePath(pLoopPlot, 0, true, &iPathTurns))
										{
											iValue *= 1000;

											iValue /= (iPathTurns + 2);

											if (iValue > iBestValue)
											{
												if ( !exposedToDanger(pLoopPlot, 60, true) && !exposedToDanger(getPathEndTurnPlot(), 60, true) )
												{
													iBestValue = iValue;
													pBestPlot = getPathEndTurnPlot();
													pBestGuardPlot = pLoopPlot;
													FAssert(atPlot(pBestGuardPlot) || !atPlot(pBestPlot));
												}
											}
										}
									}
								}
							}
						}
					}
					else
					{
						pBestPlot = pPlot;
						pBestGuardPlot = pPlot;
					}

					if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
					{
						CvSelectionGroup* pOldGroup = getGroup();
						CvUnit* pEjectedUnit = getGroup()->AI_ejectBestDefender(pBestGuardPlot);
						
						if (pEjectedUnit == NULL)
						{
							//	Mark this group as part of the city garrison
							getGroup()->AI_setAsGarrison(pCity);

							//	Not an ideal defensive candidate - is there a decent attack if the city
							//	really feels it needs us as part of it (active?) defense?
							if ( AI_anyAttack(2, 55) )
							{
								return true;
							}

							//	Ok, no attacks so I guess we'll defend as best we can
							pEjectedUnit = getGroup()->AI_ejectBestDefender(pBestGuardPlot, true);
						}
						if (pEjectedUnit != NULL)
						{
							CvPlot* missionPlot = (bGuardInCity ? pBestGuardPlot : pBestPlot);
							if ( bGuardInCity )
							{
								if (pPlot->plotCount(PUF_isCityAIType, -1, -1, getOwnerINLINE()) == 0)
								{
									if (pEjectedUnit->cityDefenseModifier() > 0)
									{
										FAssert(pEjectedUnit->AI_getUnitAIType() != UNITAI_HUNTER);
										pEjectedUnit->AI_setUnitAIType(UNITAI_CITY_DEFENSE);
									}
								}
							}
							if ( atPlot(pBestGuardPlot) )
							{
								//	Mark the ejected unit as part of the city garrison
								pEjectedUnit->getGroup()->AI_setAsGarrison(pCity);
								pEjectedUnit->getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
								return (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this);
							}
							else if ( pEjectedUnit->generatePath(missionPlot, 0, true) )
							{
								//	Mark the ejected unit as part of the city garrison
								pEjectedUnit->getGroup()->AI_setAsGarrison(pCity);
								pEjectedUnit->getGroup()->pushMission(MISSION_MOVE_TO, missionPlot->getX_INLINE(), missionPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
								return (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this);
							}
							else
							{
								//	If we can't move after all regroup
								pEjectedUnit->joinGroup(pOldGroup);
								return false;
							}
						}
						else
						{
							return false;
						}
					}
					else
					{
						//This unit is not suited for defense, skip the mission
						//to protect this city but encourage others to defend instead.
						getGroup()->pushMission(MISSION_SKIP);
						finishMoves();
					}
					return true;
				}
			}
		}
	}

	if (bSearch)
	{
		iBestValue = MAX_INT;
		pBestPlot = NULL;
		pBestGuardPlot = NULL;

		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
			if (AI_plotValid(pLoopCity->plot()))
			{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
				// BBAI efficiency: check area for land units
				if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
				{
					continue;
				}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
				int iExtra = !AI_isCityAIType() ? pLoopCity->plot()->plotStrength(UNITVALUE_FLAGS_DEFENSIVE, PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isNotCityAIType) : 0;
				bool bNeedsMilitaryHappy = isMilitaryHappiness() && !pLoopCity->AI_isAdequateHappinessMilitary();
				if (!pLoopCity->AI_isDefended(iExtra, true) || bNeedsMilitaryHappy)
				{
					if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
					{
						if ((GC.getGame().getGameTurn() - pLoopCity->getGameTurnAcquired() < 10) || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_CITY, getGroup()) < 2)
						{
							if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
							{
								if (iPathTurns <= iMaxPath)
								{
									iValue = iPathTurns;

									if (iValue < iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
										pBestGuardPlot = pLoopCity->plot();
										FAssert(!atPlot(pBestPlot));
									}
								}
							}
						}
					}
				}

				if (pBestPlot != NULL)
				{
					break;
				}
			}
		}

		if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
		{
			FAssert(!atPlot(pBestPlot));
			// split up group if we are going to defend, so rest of group has opportunity to do something else
//			if (getGroup()->getNumUnits() > 1)
//			{
//				getGroup()->AI_separate();	// will change group
//			}
//
//			getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
//			return true;

			CvSelectionGroup* pOldGroup = getGroup();
			CvUnit* pEjectedUnit = getGroup()->AI_ejectBestDefender(pBestGuardPlot);
			
			if (pEjectedUnit != NULL)
			{
				if (pEjectedUnit->getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL))
				{
					if (pEjectedUnit->getGroup() == pOldGroup || pEjectedUnit == this)
					{
						return true;
					}
					else
					{
						return false;
					}
				}
				else
				{
					pEjectedUnit->joinGroup(pOldGroup);
					return false;
				}
			}
			else
			{
				//This unit is not suited for defense, skip the mission
				//to protect this city but encourage others to defend instead.
				if (atPlot(pBestGuardPlot))
				{
					getGroup()->pushMission(MISSION_SKIP);
					return true;
				}
				else
				{
					return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, NULL);
				}
			}
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_guardCityAirlift()
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iLoop;

	if (getGroup()->getNumUnits() > 1)
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getMaxAirlift() == 0)
	{
		return false;
	}

	iBestValue = 0;
	pBestPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (pLoopCity != pCity)
		{
			if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
			{
				if (!(pLoopCity->AI_isDefended((!AI_isCityAIType()) ? pLoopCity->plot()->plotStrength(UNITVALUE_FLAGS_DEFENSIVE, PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isNotCityAIType) : 0)))	// XXX check for other team's units?
				{
					iValue = pLoopCity->getPopulation();

					if (pLoopCity->AI_isDanger())
					{
						iValue *= 2;
					}

					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						pBestPlot = pLoopCity->plot();
						FAssert(pLoopCity != pCity);
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_guardBonus(int iMinValue)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestGuardPlot;
	BonusTypes eNonObsoleteBonus;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestGuardPlot = NULL;

	const std::map<int,BonusTypes>& guardableResourcePlots = GET_PLAYER(getOwnerINLINE()).getGuardableResourcePlots();
	std::multimap<int,int> sortedIndex;

	//	A valuable optimization is possible to avoid generating the paths for all candidate resource plots (which is the expensive part).
	//	If a plot couldn't beat the best one already evaluated even with a path distance of 1 there is no need to evaluate its path.
	//	In practise this happens a LOT because the AI sends units to guard resources, then re-evaluates every turn so they are mostly
	//	already in the right place.  To ensure an evaluation order that makes this optimization likely we sort on simple plot distance
	for (std::map<int,BonusTypes>::const_iterator itr = guardableResourcePlots.begin(); itr != guardableResourcePlots.end(); ++itr)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(itr->first);

		sortedIndex.insert(std::pair<int,int>(stepDistance(getX_INLINE(),getY_INLINE(),pLoopPlot->getX_INLINE(),pLoopPlot->getY_INLINE()), itr->first));
	}

	for (std::multimap<int,int>::const_iterator itr = sortedIndex.begin(); itr != sortedIndex.end(); ++itr)
	{
		PROFILE("AI_guardBonus.LoopOuter");

		iI = itr->second;

		std::map<int,BonusTypes>::const_iterator searchItr = guardableResourcePlots.find(iI);
		FAssert( searchItr != guardableResourcePlots.end());
		eNonObsoleteBonus = searchItr->second;

		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (AI_plotValid(pLoopPlot))
		{
			iValue = GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);

			iValue += std::max(0, 200 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());

			if (pLoopPlot->getPlotGroupConnectedBonus(getOwnerINLINE(), eNonObsoleteBonus) == 1)
			{
				iValue *= 2;
			}

			if (iValue > iMinValue)
			{
				PROFILE("AI_guardBonus.HasValue");

				if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this)))
				{
					PROFILE("AI_guardBonus.NoVisibleEnemy");

					// BBAI TODO: Multiple defenders for higher value resources?
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) == 0)
					{
						//	Can this possibly beat the best we already have?
						iValue *= 1000;

						//	Path length from a plot to itself (empirically) returns 1, hence the '3' rather than '2'
						if ( iValue/3 > iBestValue )
						{
							PROFILE("AI_guardBonus.TestPath");

							if (generatePath(pLoopPlot, 0, true, &iPathTurns))
							{
								OutputDebugString(CvString::format("Evaluate guard path from (%d,%d) to (%d,%d), turns=%d, value=%d\n",
																   getX_INLINE(),getY_INLINE(),
																   pLoopPlot->getX_INLINE(),
																   pLoopPlot->getY_INLINE(),
																   iPathTurns,
																   iValue).c_str());

								iValue /= (iPathTurns + 1);

								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = getPathEndTurnPlot();
									pBestGuardPlot = pLoopPlot;
								}
							}
						}
						else
						{
							OutputDebugString(CvString::format("Resource at (%d,%d) with value %d cannot beat best value so far of %d\n",
															    pLoopPlot->getX_INLINE(),
																pLoopPlot->getY_INLINE(),
																iValue,
																iBestValue).c_str());
											  
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
	{
		if (atPlot(pBestGuardPlot))
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
		}
	}

	return false;
}

int CvUnitAI::AI_getPlotDefendersNeeded(CvPlot* pPlot, int iExtra)
{
	int iNeeded = iExtra;
	BonusTypes eNonObsoleteBonus = pPlot->getNonObsoleteBonusType(getTeam());
	if (eNonObsoleteBonus != NO_BONUS)
	{
		iNeeded += (GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus) + 10) / 19;
	}

	int iDefense = pPlot->defenseModifier(getTeam(), true);

	iNeeded += (iDefense + 25) / 50;
/************************************************************************************************/
/* Afforess	                  Start		 6/22/11                                                */
/*                                                                                              */
/* Encourage Fort Defense                                                                       */
/************************************************************************************************/
	if (pPlot->getImprovementType() != NO_IMPROVEMENT && GC.getImprovementInfo((ImprovementTypes)pPlot->getImprovementType()).isActsAsCity())
	{
		iNeeded = std::max(1, iNeeded);
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	if (iNeeded == 0)
	{
		return 0;
	}

	iNeeded += GET_PLAYER(getOwnerINLINE()).AI_getPlotAirbaseValue(pPlot) / 50;

	int iNumHostiles = 0;
	int iNumPlots = 0;

	int iRange = 2;
	for (int iX = -iRange; iX <= iRange; iX++)
	{
		for (int iY = -iRange; iY <= iRange; iY++)
		{
			CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iX, iY);
			if (pLoopPlot != NULL)
			{
				iNumHostiles += pLoopPlot->getNumVisibleEnemyDefenders(this);
				if ((pLoopPlot->getTeam() != getTeam()) || pLoopPlot->isCoastalLand())
				{
				    iNumPlots++;
                    if (isEnemy(pLoopPlot->getTeam()))
                    {
                        iNumPlots += 4;
                    }
				}
			}
		}
	}

	if ((iNumHostiles == 0) && (iNumPlots < 4))
	{
		if (iNeeded > 1)
		{
			iNeeded = 1;
		}
		else
		{
			iNeeded = 0;
		}
	}

	return iNeeded;
}

bool CvUnitAI::AI_guardFort(bool bSearch)
{
	PROFILE_FUNC();
	
	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		ImprovementTypes eImprovement = plot()->getImprovementType();
		if (eImprovement != NO_IMPROVEMENT)
		{
			if (GC.getImprovementInfo(eImprovement).isActsAsCity())
			{
				if (plot()->plotCount(PUF_isCityAIType, -1, -1, getOwnerINLINE()) <= AI_getPlotDefendersNeeded(plot(), 0))
				{
					getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, plot());
					return true;
				}
			}
		}
	}
	
	if (!bSearch)
	{
		return false;
	}

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestGuardPlot = NULL;
	CvPlot* pLoopPlot;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		//	Koshling - AI_plotValid() call not needed when using a CvReachablePlotSet
		if (/*AI_plotValid(pLoopPlot) &&*/ !atPlot(pLoopPlot) && pLoopPlot->area() == area())
		{
			if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
			{
				ImprovementTypes eImprovement = pLoopPlot->getImprovementType();
				if (eImprovement != NO_IMPROVEMENT)
				{
					if (GC.getImprovementInfo(eImprovement).isActsAsCity())
					{
						int iValue = AI_getPlotDefendersNeeded(pLoopPlot, 0);

						if (iValue > 0)
						{
/************************************************************************************************/
/* Afforess	                  Start		 6/22/11                                                */
/*                                                                                              */
/* Don't be a sissy, fight for the high ground                                                  */
/************************************************************************************************/
/*
							if (!(pLoopPlot->isVisibleEnemyUnit(this)))
*/
							if (!AI_isPlotWellDefended(pLoopPlot, true, 30))
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
							{
								if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_BONUS, getGroup()) < iValue)
								{
									int iPathTurns;
									if (generatePath(pLoopPlot, 0, true, &iPathTurns))
									{
										iValue *= 1000;

										iValue /= (iPathTurns + 2);

										if (iValue > iBestValue)
										{
											iBestValue = iValue;
											pBestPlot = getPathEndTurnPlot();
											pBestGuardPlot = pLoopPlot;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
	{
		if (atPlot(pBestGuardPlot))
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_BONUS, pBestGuardPlot);
		}
	}

	return false;
}
// Returns true if a mission was pushed...
bool CvUnitAI::AI_guardCitySite()
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestGuardPlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestGuardPlot = NULL;

	for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
	{
		pLoopPlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
		if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_GUARD_CITY, getGroup()) == 0)
		{
			if (generatePath(pLoopPlot, 0, true, &iPathTurns))
			{
				iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
				if (iValue > iBestValue)
				{
					iBestValue = iValue;
					pBestPlot = getPathEndTurnPlot();
					pBestGuardPlot = pLoopPlot;
				}
			}
		}
	}
	
	if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
	{
		if (atPlot(pBestGuardPlot))
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestGuardPlot);
		}
	}

	return false;
}



// Returns true if a mission was pushed...
bool CvUnitAI::AI_guardSpy(int iRandomPercent)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestGuardPlot;
	int iValue;
	int iBestValue;
	int iLoop;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestGuardPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (AI_plotValid(pLoopCity->plot()))
		{
			if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
			{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
				// BBAI efficiency: check area for land units
				if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
				{
					continue;
				}

				iValue = 0;

				if( GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_SPACE4) )
				{
					if( pLoopCity->isCapital() )
					{
						iValue += 30;
					}
					else if( pLoopCity->isProductionProject() )
					{
						iValue += 5;
					}
				}

				if( GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3) )
				{
					if( pLoopCity->getCultureLevel() >= (GC.getNumCultureLevelInfos() - 2))
					{
						iValue += 10;
					}
				}
				
				if (pLoopCity->isProductionUnit())
				{
					if (isLimitedUnitClass((UnitClassTypes)(GC.getUnitInfo(pLoopCity->getProductionUnit()).getUnitClassType())))
					{
						iValue += 4;
					}
				}
				else if (pLoopCity->isProductionBuilding())
				{
					if (isLimitedWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType())))
					{
						iValue += 5;
					}
				}
				else if (pLoopCity->isProductionProject())
				{
					if (isLimitedProject(pLoopCity->getProductionProject()))
					{
						iValue += 6;
					}
				}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

				if (iValue > 0)
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GUARD_SPY, getGroup()) == 0)
					{
						int iPathTurns;
						if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
						{
							iValue *= 100 + GC.getGameINLINE().getSorenRandNum(iRandomPercent, "AI Guard Spy");
							//iValue /= 100;
							iValue /= iPathTurns + 1;

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = getPathEndTurnPlot();
								pBestGuardPlot = pLoopCity->plot();
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestGuardPlot != NULL))
	{
		if (atPlot(pBestGuardPlot))
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_GUARD_SPY, pBestGuardPlot);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_SPY, pBestGuardPlot);
		}
	}

	return false;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/25/09                                jdog5000      */
/*                                                                                              */
/* Espionage AI                                                                                 */
/************************************************************************************************/					
/*
// Never used BTS functions ... 

// Returns true if a mission was pushed...
bool CvUnitAI::AI_destroySpy()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvCity* pBestCity;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestCity = NULL;

	for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive())
		{
			if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
			{
				if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
				{
					for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
					{
						if (AI_plotValid(pLoopCity->plot()))
						{
							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ATTACK_SPY, getGroup()) == 0)
							{
								if (generatePath(pLoopCity->plot(), 0, true))
								{
									iValue = (pLoopCity->getPopulation() * 2);

									iValue += pLoopCity->getYieldRate(YIELD_PRODUCTION);

									if (atPlot(pLoopCity->plot()))
									{
										iValue *= 4;
										iValue /= 3;
									}

									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
										pBestCity = pLoopCity;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestCity != NULL))
	{
		if (atPlot(pBestCity->plot()))
		{
			if (canDestroy(pBestCity->plot()))
			{
				if (pBestCity->getProduction() > ((pBestCity->getProductionNeeded() * 2) / 3))
				{
					if (pBestCity->isProductionUnit())
					{
						if (isLimitedUnitClass((UnitClassTypes)(GC.getUnitInfo(pBestCity->getProductionUnit()).getUnitClassType())))
						{
							getGroup()->pushMission(MISSION_DESTROY);
							return true;
						}
					}
					else if (pBestCity->isProductionBuilding())
					{
						if (isLimitedWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pBestCity->getProductionBuilding()).getBuildingClassType())))
						{
							getGroup()->pushMission(MISSION_DESTROY);
							return true;
						}
					}
					else if (pBestCity->isProductionProject())
					{
						if (isLimitedProject(pBestCity->getProductionProject()))
						{
							getGroup()->pushMission(MISSION_DESTROY);
							return true;
						}
					}
				}
			}

			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pBestCity->plot());
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestCity->plot());
			return true;
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_sabotageSpy()
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestSabotagePlot;
	bool abPlayerAngry[MAX_PLAYERS];
	ImprovementTypes eImprovement;
	BonusTypes eNonObsoleteBonus;
	int iValue;
	int iBestValue;
	int iI;

	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
		abPlayerAngry[iI] = false;

		if (GET_PLAYER((PlayerTypes)iI).isAlive())
		{
			if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
			{
				if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
				{
					abPlayerAngry[iI] = true;
				}
			}
		}
	}

	iBestValue = 0;
	pBestPlot = NULL;
	pBestSabotagePlot = NULL;

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (AI_plotValid(pLoopPlot))
		{
			if (pLoopPlot->isOwned())
			{
				if (pLoopPlot->getTeam() != getTeam())
				{
					if (abPlayerAngry[pLoopPlot->getOwnerINLINE()])
					{
						eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(pLoopPlot->getTeam());

						if (eNonObsoleteBonus != NO_BONUS)
						{
							eImprovement = pLoopPlot->getImprovementType();

							if ((eImprovement != NO_IMPROVEMENT) && GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
							{
								if (canSabotage(pLoopPlot))
								{
									iValue = GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);

									if (pLoopPlot->isConnectedToCapital() && (pLoopPlot->getPlotGroupConnectedBonus(pLoopPlot->getOwnerINLINE(), eNonObsoleteBonus) == 1))
									{
										iValue *= 3;
									}

									if (iValue > 25)
									{
										if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup()) == 0)
										{
											if (generatePath(pLoopPlot, 0, true))
											{
												if (iValue > iBestValue)
												{
													iBestValue = iValue;
													pBestPlot = getPathEndTurnPlot();
													pBestSabotagePlot = pLoopPlot;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestSabotagePlot != NULL))
	{
		if (atPlot(pBestSabotagePlot))
		{
			getGroup()->pushMission(MISSION_SABOTAGE);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSabotagePlot);
			return true;
		}
	}

	return false;
}


bool CvUnitAI::AI_pickupTargetSpy()
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestPickupPlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		if (pCity->getOwnerINLINE() == getOwnerINLINE())
		{
			if (pCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
			{
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY, pCity->plot());
				return true;
			}
		}
	}

	iBestValue = MAX_INT;
	pBestPlot = NULL;
	pBestPickupPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (AI_plotValid(pLoopCity->plot()))
		{
			if (pLoopCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
					if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
					{
						iValue = iPathTurns;

						if (iValue < iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = getPathEndTurnPlot();
							pBestPickupPlot = pLoopCity->plot();
							FAssert(!atPlot(pBestPlot));
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestPickupPlot != NULL))
	{
		FAssert(!atPlot(pBestPlot));
		getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestPickupPlot);
		return true;
	}

	return false;
}
*/
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


// Returns true if a mission was pushed...
bool CvUnitAI::AI_chokeDefend()
{
	CvCity* pCity;
	int iPlotDanger;

	FAssert(AI_isCityAIType());

	// XXX what about amphib invasions?

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		if (pCity->getOwnerINLINE() == getOwnerINLINE())
		{
			if (pCity->AI_neededDefenders() > 1)
			{
				if (pCity->AI_isDefended(pCity->plot()->plotStrength(UNITVALUE_FLAGS_DEFENSIVE, PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isNotCityAIType)))
				{
					iPlotDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 3);

					if (iPlotDanger <= 4)
					{
						if (AI_anyAttack(1, 65, std::max(0, (iPlotDanger - 1))))
						{
							return true;
						}
					}
				}
			}
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_heal(int iDamagePercent, int iMaxPath)
{
	PROFILE_FUNC();

	CLLNode<IDInfo>* pEntityNode;
	std::vector<CvUnit*> aeDamagedUnits;
	CvSelectionGroup* pGroup;
	CvUnit* pLoopUnit;
	int iTotalDamage;
	int iTotalHitpoints;
	int iHurtUnitCount;
	bool bRetreat;
/************************************************************************************************/
/* Afforess	                  Start		 08/02/10                                               */
/*                                                                                              */
/* Fixed Borders AI                                                                             */
/************************************************************************************************/
	bool bCanClaimTerritory = canClaimTerritory(plot());
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/	
	if (plot()->getFeatureTurnDamage() > 0)
	{
		//Pass through
		//(actively seeking a safe spot may result in unit getting stuck)
		OutputDebugString("AI_heal: denying heal due to feature damage\n");
		return false;
	}
/************************************************************************************************/
/* Afforess	                  Start		 05/17/10                                                */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	if (plot()->getTerrainTurnDamage(getGroup()) > 0)
	{
		OutputDebugString("AI_heal: denying heal due to terrain damage\n");
		return false;
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	pGroup = getGroup();
	
	if (iDamagePercent == 0)
	{
	    iDamagePercent = 10;	    
	}	

	bRetreat = false;
	
    if (getGroup()->getNumUnits() == 1)
	{
	    if (getDamage() > 0)
        {
			OutputDebugString("AI_heal: one unit stack\n");
            if (plot()->isCity() || (healTurns(plot()) == 1))
            {
                if (!(isAlwaysHeal()))
                {
					OutputDebugString("AI_heal: city or 1 turn heal\n");
                    getGroup()->pushMission(MISSION_HEAL);
                    return true;
                }
            }
/************************************************************************************************/
/* Afforess	                  Start		 06/11/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
			if (plot()->getNumVisibleAdjacentEnemyDefenders(this) == 0 && !isAlwaysHeal())
			{
				OutputDebugString("AI_heal: no adjacent defenders\n");
				//	Koshling - this was causing more death than it was saving, especially now that
				//	explorer and engineer callers do a safety check before attempting to heal
				//if (!noDefensiveBonus() || GC.getGameINLINE().getSorenRandNum(3, "AI Heal"))
				{
					OutputDebugString(CvString::format("AI_heal: noDefensiveBonus()=%d, considering heal\n",noDefensiveBonus()).c_str());
					if (plot()->getTeam() == NO_TEAM || !GET_TEAM(plot()->getTeam()).isAtWar(getTeam()))
					{
						if (!plot()->isCity() && AI_moveIntoCity(1))
						{
							OutputDebugString("AI_heal: one turn city move\n");
							return true;
						}
						else
						{
							OutputDebugString("AI_heal: healing\n");
							getGroup()->pushMission(MISSION_HEAL);
							return true;
						}
					}
				}
				//else
				//{
				//	OutputDebugString(CvString::format("AI_heal: noDefensiveBonus()=%d, NOT healing\n",noDefensiveBonus()).c_str());
				//}
			}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/

			OutputDebugString("AI_heal: denying heal\n");
        }
        return false;
	}
	
	iMaxPath = std::min(iMaxPath, 2);

	pEntityNode = getGroup()->headUnitNode();

    iTotalDamage = 0;
    iTotalHitpoints = 0;
    iHurtUnitCount = 0;
	while (pEntityNode != NULL)
	{
		pLoopUnit = ::getUnit(pEntityNode->m_data);
		FAssert(pLoopUnit != NULL);
		pEntityNode = pGroup->nextUnitNode(pEntityNode);

		int iDamageThreshold = (pLoopUnit->maxHitPoints() * iDamagePercent) / 100;

		if (NO_UNIT != getLeaderUnitType())
		{
			iDamageThreshold /= 2;
		}
		
		if (pLoopUnit->getDamage() > 0)
		{
		    iHurtUnitCount++;
		}
		iTotalDamage += pLoopUnit->getDamage();
		iTotalHitpoints += pLoopUnit->maxHitPoints();
		

		if (pLoopUnit->getDamage() > iDamageThreshold)
		{
			bRetreat = true;

			if (!(pLoopUnit->hasMoved()))
			{
				if (!(pLoopUnit->isAlwaysHeal()))
				{
					if (pLoopUnit->healTurns(pLoopUnit->plot()) <= iMaxPath)
					{
					    aeDamagedUnits.push_back(pLoopUnit);
					}
				}
			}
		}
	}
	if (iHurtUnitCount == 0)
	{
	    return false;
	}
	
	bool bPushedMission = false;
/************************************************************************************************/
/* Afforess	                  Start		 08/02/10                                               */
/*                                                                                              */
/* Fixed Borders AI                                                                             */
/************************************************************************************************/
/*
    if (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE()))
*/
	 if ( (plot()->isCity() && (plot()->getOwnerINLINE() == getOwnerINLINE())) || bCanClaimTerritory)
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	{
		FAssertMsg(((int) aeDamagedUnits.size()) <= iHurtUnitCount, "damaged units array is larger than our hurt unit count");

		for (unsigned int iI = 0; iI < aeDamagedUnits.size(); iI++)
		{
			CvUnit* pUnitToHeal = aeDamagedUnits[iI];
			pUnitToHeal->joinGroup(NULL);
			pUnitToHeal->getGroup()->pushMission(MISSION_HEAL);

			// note, removing the head unit from a group will force the group to be completely split if non-human
			if (pUnitToHeal == this)
			{ 
				bPushedMission = true;
/************************************************************************************************/
/* Afforess	                  Start		 08/02/10                                               */
/*                                                                                              */
/* Fixed Borders AI                                                                             */
/************************************************************************************************/
				if (canClaimTerritory(plot()))
				{
					getGroup()->pushMission(MISSION_CLAIM_TERRITORY, -1, -1, 0, false, false, MISSIONAI_CLAIM_TERRITORY, plot());
					getGroup()->pushMission(MISSION_HEAL, -1, -1, 0, true, false);
				}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
			}

			iHurtUnitCount--;
		}
	}
	
	if ((iHurtUnitCount * 2) > pGroup->getNumUnits())
	{
		FAssertMsg(pGroup->getNumUnits() > 0, "group now has zero units");
	
	    if (AI_moveIntoCity(2))
		{
			return true;
		}
		else if (healRate(plot()) > 10)
	    {
            pGroup->pushMission(MISSION_HEAL);
            return true;
	    }
		else
		{
			if ( AI_safety(iMaxPath) )
			{
				return true;
			}
		}
	}
	
	return bPushedMission;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_afterAttack()
{
	if (!isMadeAttack())
	{
		return false;
	}
	
	if (!canFight())
	{
		return false;
	}

	if (isBlitz())
	{
		return false;
	}

	if (getDomainType() == DOMAIN_LAND)
	{
		if (AI_guardCity(false, true, 1))
		{
			return true;
		}
	}
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment plot AI
	// Dale - RB: Field Bombard START
	if (AI_RbombardPlot(getDCMBombRange(), 60))
	{
		return true;
	}
	// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                            END                                     Glider1     */
/************************************************************************************************/

	if (AI_pillageRange(1))
	{
		return true;
	}

	if (AI_retreatToCity(false, false, 1))
	{
		return true;
	}

	if (AI_hide())
	{
		return true;
	}

	if (AI_goody(1))
	{
		return true;
	}
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment plot AI
	// Dale - RB: Field Bombard START
	if (AI_RbombardPlot(getDCMBombRange(), 0))
	{
		return true;
	}
	// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                            END                                     Glider1     */
/************************************************************************************************/

	if (AI_pillageRange(2))
	{
		return true;
	}

	if (AI_defend())
	{
		return true;
	}

	if (AI_safety())
	{
		return true;
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_goldenAge()
{
	if (canGoldenAge(plot()))
	{
		getGroup()->pushMission(MISSION_GOLDEN_AGE);
		return true;
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_spreadReligion()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestSpreadPlot;
	ReligionTypes eReligion;
	int iValue;
	int iBestValue;
	int iPlayerMultiplierPercent;
	int iLoop;
	int iI;
	int iBaseFlags = (isHuman() ? MOVE_NO_ENEMY_TERRITORY : (MOVE_NO_ENEMY_TERRITORY | MOVE_IGNORE_DANGER));

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/08/10                                jdog5000      */
/*                                                                                              */
/* Victory Strategy AI                                                                          */
/************************************************************************************************/
	bool bCultureVictory = GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE2);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	eReligion = NO_RELIGION;

	// BBAI TODO: Unnecessary with changes below ...
	if (eReligion == NO_RELIGION)
	{
		if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != NO_RELIGION)
		{
			if (m_pUnitInfo->getReligionSpreads(GET_PLAYER(getOwnerINLINE()).getStateReligion()) > 0)
			{
				eReligion = GET_PLAYER(getOwnerINLINE()).getStateReligion();
			}
		}
	}

	if (eReligion == NO_RELIGION)
	{
		for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
		{
			//if (bCultureVictory || GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI))
			{
				if (m_pUnitInfo->getReligionSpreads((ReligionTypes)iI) > 0)
				{
					eReligion = ((ReligionTypes)iI);
					break;
				}
			}
		}
	}

	if (eReligion == NO_RELIGION)
	{
		return false;
	}

	bool bHasHolyCity = GET_TEAM(getTeam()).hasHolyCity(eReligion);
	bool bHasAnyHolyCity = bHasHolyCity;
	if (!bHasAnyHolyCity)
	{
		for (iI = 0; !bHasAnyHolyCity && iI < GC.getNumReligionInfos(); iI++)
		{
			bHasAnyHolyCity = GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI);
		}
	}

	iBestValue = 0;
	pBestPlot = NULL;
	pBestSpreadPlot = NULL;

	if ( m_cachedPlayer != getOwnerINLINE() ||
		 m_cachedMissionaryPlotset == NULL ||
		 m_cachedMissionaryPlotset->find(plot()) == m_cachedMissionaryPlotset->end() )
	{
		SAFE_DELETE(m_cachedMissionaryPlotset);

		m_cachedMissionaryPlotset = new CvReachablePlotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, MAX_INT, false);

		m_cachedPlayer = getOwnerINLINE();
	}

	//CvReachablePlotSet plotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, MAX_INT);
	std::multimap<int,CvCity*>	targetValues;
	CvReachablePlotSet::const_iterator itr = m_cachedMissionaryPlotset->begin();

	//	If we already has a chosen spread city targeted then start with a presumption
	//	we'll stick to it
	if ( getGroup()->AI_getMissionAIType() == MISSIONAI_SPREAD )
	{
		PROFILE("CvUnitAI::AI_spreadReligion.AlreadyMissioned");

		CvPlot*	pPlot = getGroup()->AI_getMissionAIPlot();

		pLoopCity = pPlot->getPlotCity();

		//logBBAI("Missionary %d at (%d,%d) already targeting city at (%d,%d)\n", getID(), plot()->getX_INLINE(), plot()->getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE());

		if ( pLoopCity != NULL &&
			 m_cachedMissionaryPlotset->find(pLoopCity->plot()) != m_cachedMissionaryPlotset->end() &&
			 generatePath(pLoopCity->plot(), iBaseFlags, true) )
		{
			bool bForceMove = false;
			if (isHuman())
			{
				//If human, prefer to spread to the player where automated from.
				if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
				{
					if (pLoopCity->isRevealed(getTeam(), false))
					{
						bForceMove = true;
					}
				}
			}

			pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
			pBestSpreadPlot = pLoopCity->plot();

			//	Check end of turn point is not in immediate danger
			if ( !bForceMove && GET_PLAYER(getOwnerINLINE()).AI_getVisiblePlotDanger(pBestPlot, 1, false) )
			{
				//logBBAI("Danger at end turn plot - looking for alternate route...");
				//	Try to find an alternate route taking danger into account in the
				//	apthing calculation
				if ( generatePath(pLoopCity->plot(),
								  MOVE_NO_ENEMY_TERRITORY,
								  true))
				{
					//logBBAI("...found one");
					pBestPlot = getPathEndTurnPlot();

					iBaseFlags = MOVE_NO_ENEMY_TERRITORY;
				}
				else
				{
					//	No way past
					//logBBAI("...none found!");
					pBestSpreadPlot = NULL;
				}
			}
		}
	}

	if ( pBestSpreadPlot == NULL )
	{
		// BBAI TODO: Could also use CvPlayerAI::AI_missionaryValue to determine which player to target ...
		for (iI = 0; iI < MAX_PLAYERS; iI++)
		{
			if (GET_PLAYER((PlayerTypes)iI).isAlive())
			{
				iPlayerMultiplierPercent = 0;

	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      11/28/09                                jdog5000      */
	/*                                                                                              */
	/* Unit AI, Efficiency                                                                          */
	/************************************************************************************************/
				//if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
				if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam() && canEnterTerritory(GET_PLAYER((PlayerTypes)iI).getTeam()))
				{
					if (bHasHolyCity)
					{
						iPlayerMultiplierPercent = 100;
						// BBAI TODO: If going for cultural victory, don't spread to other teams?  Sure, this might decrease the chance of 
						// someone else winning by culture, but at the cost of $$ in holy city and diplomatic conversions (ie future wars!).  
						// Doesn't seem to up our odds of winning by culture really.  Also, no foreign spread after Free Religion?  Still get
						// gold for city count.
						if (!bCultureVictory || (eReligion == GET_PLAYER(getOwnerINLINE()).getStateReligion()))
						{
							if (GET_PLAYER((PlayerTypes)iI).getStateReligion() == NO_RELIGION)
							{
								if (0 == (GET_PLAYER((PlayerTypes)iI).getNonStateReligionHappiness()))
								{
									iPlayerMultiplierPercent += 600;
								}
							}
							else if (GET_PLAYER((PlayerTypes)iI).getStateReligion() == eReligion)
							{
								iPlayerMultiplierPercent += 300;
							}
							else
							{
								if (GET_PLAYER((PlayerTypes)iI).hasHolyCity(GET_PLAYER((PlayerTypes)iI).getStateReligion()))
								{
									iPlayerMultiplierPercent += 50;
								}
								else
								{
									iPlayerMultiplierPercent += 300;
								}
							}
							
							int iReligionCount = GET_PLAYER((PlayerTypes)iI).countTotalHasReligion();
							int iCityCount = GET_PLAYER(getOwnerINLINE()).getNumCities();
							//magic formula to produce normalized adjustment factor based on religious infusion
							int iAdjustment = (100 * (iCityCount + 1));
							iAdjustment /= ((iCityCount + 1) + iReligionCount);
							iAdjustment = (((iAdjustment - 25) * 4) / 3);
							
							iAdjustment = std::max(10, iAdjustment);
							
							iPlayerMultiplierPercent *= iAdjustment;
							iPlayerMultiplierPercent /= 100;
						}
					}
				}
				else if (iI == getOwnerINLINE())
				{
					iPlayerMultiplierPercent = 100;
				}
				else if (bHasHolyCity && GET_PLAYER((PlayerTypes)iI).getTeam() == getTeam())
				{
					iPlayerMultiplierPercent = 80;
				}
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/
				
				if (iPlayerMultiplierPercent > 0)
				{
					for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
					{
						if (AI_plotValid(pLoopCity->plot()) && (itr = m_cachedMissionaryPlotset->find(pLoopCity->plot())) != m_cachedMissionaryPlotset->end())
						{
							if (canSpread(pLoopCity->plot(), eReligion))
							{
								if (!GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pLoopCity->plot()))
								{
									if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD, getGroup()) == 0)
									{
										iValue = (7 + (pLoopCity->getPopulation() * 4));

										bool bOurCity = false;
										// BBAI TODO: Why not just use iPlayerMultiplier??
										if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
										{
											iValue *= (bCultureVictory ? 16 : 4);
											bOurCity = true;
										}
										else if (pLoopCity->getTeam() == getTeam())
										{
											iValue *= 3;
											bOurCity = true;
										}
										else
										{
											iValue *= iPlayerMultiplierPercent;
											iValue /= 100;
										}
										
										int iCityReligionCount = pLoopCity->getReligionCount();
										int iReligionCountFactor = iCityReligionCount;

										if (bOurCity)
										{
											// count cities with no religion the same as cities with 2 religions
											// prefer a city with exactly 1 religion already
											if (iCityReligionCount == 0)
											{
												iReligionCountFactor = 2;
											}
											else if (iCityReligionCount == 1)
											{
												iValue *= 2;
											}
										}
										else
										{
											// absolutely prefer cities with zero religions
											if (iCityReligionCount == 0)
											{
												iValue *= 2;
											}

											// not our city, so prefer the lowest number of religions (increment so no divide by zero)
											iReligionCountFactor++;
										}

										iValue /= iReligionCountFactor;

										bool bForceMove = false;
										if (isHuman())
										{
											//If human, prefer to spread to the player where automated from.
											if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
											{
												iValue *= 10;
												if (pLoopCity->isRevealed(getTeam(), false))
												{
													bForceMove = true;
												}
											}
										}

										iValue *= 1000;

										targetValues.insert(std::pair<int,CvCity*>(-iValue/(1+itr.stepDistance()), pLoopCity));
									}
								}
							}
						}
					}
				}
			}
		}

		// Koshling - evaluate in likely best-first order to try to minimize pathing calculations
		int iEvaluated = 0;
		int iBestEvaluationFoundOn = -1;
		for(std::multimap<int,CvCity*>::const_iterator itr = targetValues.begin(); itr != targetValues.end(); ++itr)
		{
			pLoopCity = itr->second;

			if ( generatePath(pLoopCity->plot(),
							  iBaseFlags,
							  true))
			{
				bool bForceMove = false;
				if (isHuman())
				{
					// Reconstruct bForceMove value
					if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
					{
						if (pLoopCity->isRevealed(getTeam(), false))
						{
							bForceMove = true;
						}
					}
				}

				pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
				pBestSpreadPlot = pLoopCity->plot();

				//logBBAI("Potential target city at (%d,%d)", pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE());

				//	Check end of turn point is not in immediate danger
				if ( !bForceMove && GET_PLAYER(getOwnerINLINE()).AI_getVisiblePlotDanger(pBestPlot, 1, false) )
				{
					//logBBAI("Danger at end turn plot - looking for alternate route...");
					//	Try to find an alternate route taking danger into account in the
					//	apthing calculation
					if ( generatePath(pLoopCity->plot(),
									  MOVE_NO_ENEMY_TERRITORY,
									  true))
					{
						//logBBAI("...found one");
						pBestPlot = getPathEndTurnPlot();

						iBaseFlags = MOVE_NO_ENEMY_TERRITORY;
					}
					else
					{
						//	No way past
						//logBBAI("...none found!");
						continue;
					}
				}

				//	Ordering is very close to optimal in almost all conceivable cases
				//	so just take the first that works
				break;
			}
		}
	}
	else
	{
		//logBBAI("Retaining last target");
	}

	if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
	{
		//logBBAI("Missionary %d at (%d,%d) targeting spread in city at (%d,%d)\n", getID(), plot()->getX_INLINE(), plot()->getY_INLINE(), pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE());
		if (atPlot(pBestSpreadPlot))
		{
			getGroup()->pushMission(MISSION_SPREAD, eReligion);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/09/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), iBaseFlags, false, false, MISSIONAI_SPREAD, pBestSpreadPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_spreadCorporation()
{
	PROFILE_FUNC();

	CorporationTypes eCorporation = NO_CORPORATION;	
	int iBaseFlags = (isHuman() ? MOVE_NO_ENEMY_TERRITORY : (MOVE_NO_ENEMY_TERRITORY | MOVE_IGNORE_DANGER));

	for (int iI = 0; iI < GC.getNumCorporationInfos(); ++iI)
	{
		if (m_pUnitInfo->getCorporationSpreads((CorporationTypes)iI) > 0)
		{
			eCorporation = ((CorporationTypes)iI);
			break;
		}
	}

	if (NO_CORPORATION == eCorporation)
	{
		return false;
	}
/*************************************************************************************************/
/**	Xienwolf Tweak							03/20/09											**/
/**																								**/
/**										Firaxis Typo Fix										**/
/*************************************************************************************************/
/**								---- Start Original Code ----									**
	bool bHasHQ = (GET_TEAM(getTeam()).hasHeadquarters((CorporationTypes)iI));
/**								----  End Original Code  ----									**/
	bool bHasHQ = (GET_TEAM(getTeam()).hasHeadquarters(eCorporation));
/*************************************************************************************************/
/**	Tweak									END													**/
/*************************************************************************************************/

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestSpreadPlot = NULL;
	CvCity* pLoopCity;

	if ( m_cachedPlayer != getOwnerINLINE() ||
		 m_cachedMissionaryPlotset == NULL ||
		 m_cachedMissionaryPlotset->find(plot()) == m_cachedMissionaryPlotset->end() )
	{
		SAFE_DELETE(m_cachedMissionaryPlotset);

		m_cachedMissionaryPlotset = new CvReachablePlotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, MAX_INT, false);

		m_cachedPlayer = getOwnerINLINE();
	}

	//CvReachablePlotSet plotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, MAX_INT);
	std::multimap<int,CvCity*>	targetValues;
	CvReachablePlotSet::const_iterator itr = m_cachedMissionaryPlotset->begin();

	//	If we already has a chosen spread city targeted then start with a presumption
	//	we'll stick to it
	if ( getGroup()->AI_getMissionAIType() == MISSIONAI_SPREAD_CORPORATION )
	{
		PROFILE("CvUnitAI::AI_spreadReligion.AlreadyMissioned");

		CvPlot*	pPlot = getGroup()->AI_getMissionAIPlot();

		pLoopCity = pPlot->getPlotCity();

		//OutputDebugString(CvString::format("Missionary at (%d,%d) already targeting city at (%d,%d)\n", plot()->getX_INLINE(), plot()->getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()).c_str());

		if ( pLoopCity != NULL &&
			 m_cachedMissionaryPlotset->find(pLoopCity->plot()) != m_cachedMissionaryPlotset->end() &&
			 generatePath(pLoopCity->plot(), iBaseFlags, true) )
		{
			bool bForceMove = false;
			if (isHuman())
			{
				//If human, prefer to spread to the player where automated from.
				if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
				{
					if (pLoopCity->isRevealed(getTeam(), false))
					{
						bForceMove = true;
					}
				}
			}

			pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
			pBestSpreadPlot = pLoopCity->plot();

			//	Check end of turn point is not in immediate danger
			if ( !bForceMove && GET_PLAYER(getOwnerINLINE()).AI_getVisiblePlotDanger(pBestPlot, 1, false) )
			{
				//logBBAI("Danger at end turn plot - looking for alternate route...");
				//	Try to find an alternate route taking danger into account in the
				//	apthing calculation
				if ( generatePath(pLoopCity->plot(),
								  MOVE_NO_ENEMY_TERRITORY,
								  true))
				{
					//logBBAI("...found one");
					pBestPlot = getPathEndTurnPlot();

					iBaseFlags = MOVE_NO_ENEMY_TERRITORY;
				}
				else
				{
					//	No way past
					//logBBAI("...none found!");
					pBestSpreadPlot = NULL;
				}
			}
		}
	}

	if ( pBestSpreadPlot == NULL )
	{
		CvTeam& kTeam = GET_TEAM(getTeam());
		for (int iI = 0; iI < MAX_PLAYERS; iI++)
		{
			CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      08/21/09                                jdog5000      */
	/*                                                                                              */
	/* Unit AI, Efficiency                                                                          */
	/************************************************************************************************/
			//if (kLoopPlayer.isAlive() && (bHasHQ || (getTeam() == kLoopPlayer.getTeam())))
			if (kLoopPlayer.isAlive() && ((bHasHQ && canEnterTerritory(GET_PLAYER((PlayerTypes)iI).getTeam())) || (getTeam() == kLoopPlayer.getTeam())))
			{			
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/
				int iLoopPlayerCorpCount = kLoopPlayer.countCorporations(eCorporation);
				CvTeam& kLoopTeam = GET_TEAM(kLoopPlayer.getTeam());
				int iLoop;
				for (pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
				{
					if (AI_plotValid(pLoopCity->plot()) && (itr = m_cachedMissionaryPlotset->find(pLoopCity->plot())) != m_cachedMissionaryPlotset->end())
					{
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
	/*                                                                                              */
	/* Unit AI, Efficiency                                                                          */
	/************************************************************************************************/
						// BBAI efficiency: check same area
						if ( /*pLoopCity->area() == area() &&*/ canSpreadCorporation(pLoopCity->plot(), eCorporation))
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/
						{
							if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
							{
								if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
								{
									// BBAI TODO: Serious need for more intelligent self spread, keep certain corps from
									// enemies based on their victory pursuits (culture ...)
									int iValue = (10 + pLoopCity->getPopulation() * 2);

									if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
									{
										iValue *= 4;
									}
									else if (kLoopTeam.isVassal(getTeam()))
									{
										iValue *= 3;
									}
									else if (kTeam.isVassal(kLoopTeam.getID()))
									{
										if (iLoopPlayerCorpCount == 0)
										{
											iValue *= 10;
										}
										else
										{
											iValue *= 3;
											iValue /= 2;
										}
									}
									else if (pLoopCity->getTeam() == getTeam())
									{
										iValue *= 2;
									}

									if (iLoopPlayerCorpCount == 0)
									{
										//Generally prefer to heavily target one player
										iValue /= 2;
									}

									if (isHuman())
									{
										//If human, prefer to spread to the player where automated from.
										if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
										{
											iValue *= 10;
										}
									}

									iValue *= 1000;

									targetValues.insert(std::pair<int,CvCity*>(-iValue/(1+itr.stepDistance()), pLoopCity));
								}
							}
						}
					}
				}
			}
		}

		// Koshling - evaluate in likely best-first order to try to minimize pathing calculations
		int iEvaluated = 0;
		int iBestEvaluationFoundOn = -1;
		for(std::multimap<int,CvCity*>::const_iterator itr = targetValues.begin(); itr != targetValues.end(); ++itr)
		{
			pLoopCity = itr->second;

			if ( generatePath(pLoopCity->plot(),
							  iBaseFlags,
							  true))
			{
				bool bForceMove = false;
				if (isHuman())
				{
					// Reconstruct bForceMove value
					if (plot()->getOwnerINLINE() == pLoopCity->getOwnerINLINE())
					{
						if (pLoopCity->isRevealed(getTeam(), false))
						{
							bForceMove = true;
						}
					}
				}

				pBestPlot = bForceMove ? pLoopCity->plot() : getPathEndTurnPlot();
				pBestSpreadPlot = pLoopCity->plot();

				//	Check end of turn point is not in immediate danger
				if ( !bForceMove && GET_PLAYER(getOwnerINLINE()).AI_getVisiblePlotDanger(pBestPlot, 1, false) )
				{
					//logBBAI("Danger at end turn plot - looking for alternate route...");
					//	Try to find an alternate route taking danger into account in the
					//	apthing calculation
					if ( generatePath(pLoopCity->plot(),
									  MOVE_NO_ENEMY_TERRITORY,
									  true))
					{
						//logBBAI("...found one");
						pBestPlot = getPathEndTurnPlot();

						iBaseFlags = MOVE_NO_ENEMY_TERRITORY;
					}
					else
					{
						//	No way past
						//logBBAI("...none found!");
						continue;
					}
				}

				//	Ordering is very close to optimal in almost all conceivable cases
				//	so just take the first that works
				break;
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
	{
		if (atPlot(pBestSpreadPlot))
		{
			if (canSpreadCorporation(pBestSpreadPlot, eCorporation))
			{
				getGroup()->pushMission(MISSION_SPREAD_CORPORATION, eCorporation);
			}
			else
			{
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_SPREAD_CORPORATION, pBestSpreadPlot);
			}
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/09/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), iBaseFlags, false, false, MISSIONAI_SPREAD_CORPORATION, pBestSpreadPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}

bool CvUnitAI::AI_spreadReligionAirlift()
{
	PROFILE_FUNC();

	CvPlot* pBestPlot;
	ReligionTypes eReligion;
	int iValue;
	int iBestValue;
	int iI;

	if (getGroup()->getNumUnits() > 1)
	{
		return false;
	}

	CvCity* pCity = plot()->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getMaxAirlift() == 0)
	{
		return false;
	}

	//bool bCultureVictory = GET_PLAYER(getOwnerINLINE()).AI_isDoStrategy(AI_STRATEGY_CULTURE2);
	eReligion = NO_RELIGION;

	if (eReligion == NO_RELIGION)
	{
		if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != NO_RELIGION)
		{
			if (m_pUnitInfo->getReligionSpreads(GET_PLAYER(getOwnerINLINE()).getStateReligion()) > 0)
			{
				eReligion = GET_PLAYER(getOwnerINLINE()).getStateReligion();
			}
		}
	}

	if (eReligion == NO_RELIGION)
	{
		for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
		{
			//if (bCultureVictory || GET_TEAM(getTeam()).hasHolyCity((ReligionTypes)iI))
			{
				if (m_pUnitInfo->getReligionSpreads((ReligionTypes)iI) > 0)
				{
					eReligion = ((ReligionTypes)iI);
					break;
				}
			}
		}
	}

	if (eReligion == NO_RELIGION)
	{
		return false;
	}

	iBestValue = 0;
	pBestPlot = NULL;

	for (int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
		if (kLoopPlayer.isAlive() && (getTeam() == kLoopPlayer.getTeam()))
		{
			int iLoop;
			for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
			{
				if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
				{
					if (canSpread(pLoopCity->plot(), eReligion))
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD, getGroup()) == 0)
						{
/************************************************************************************************/
/* UNOFFICIAL_PATCH                       08/04/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
							// Don't airlift where there's already one of our unit types (probably just airlifted)
							if( pLoopCity->plot()->plotCount(PUF_isUnitType, getUnitType(), -1, getOwnerINLINE()) > 0 )
							{
								continue;
							}
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/
							iValue = (7 + (pLoopCity->getPopulation() * 4));
							
							int iCityReligionCount = pLoopCity->getReligionCount();
							int iReligionCountFactor = iCityReligionCount;

							// count cities with no religion the same as cities with 2 religions
							// prefer a city with exactly 1 religion already
							if (iCityReligionCount == 0)
							{
								iReligionCountFactor = 2;
							}
							else if (iCityReligionCount == 1)
							{
								iValue *= 2;
							}
							
							iValue /= iReligionCountFactor;
							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopCity->plot();
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_SPREAD, pBestPlot);
		return true;
	}

	return false;	
}

bool CvUnitAI::AI_spreadCorporationAirlift()
{
	PROFILE_FUNC();
	
	if (getGroup()->getNumUnits() > 1)
	{
		return false;
	}

	CvCity* pCity = plot()->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getMaxAirlift() == 0)
	{
		return false;
	}
	
	CorporationTypes eCorporation = NO_CORPORATION;	

	for (int iI = 0; iI < GC.getNumCorporationInfos(); ++iI)
	{
		if (m_pUnitInfo->getCorporationSpreads((CorporationTypes)iI) > 0)
		{
			eCorporation = ((CorporationTypes)iI);
			break;
		}
	}

	if (NO_CORPORATION == eCorporation)
	{
		return false;
	}

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;

	for (int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
		if (kLoopPlayer.isAlive() && (getTeam() == kLoopPlayer.getTeam()))
		{
			int iLoop;
			for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
			{
				if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
				{
					if (canSpreadCorporation(pLoopCity->plot(), eCorporation))
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
						{
/************************************************************************************************/
/* UNOFFICIAL_PATCH                       08/04/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
							// Don't airlift where there's already one of our unit types (probably just airlifted)
							if( pLoopCity->plot()->plotCount(PUF_isUnitType, getUnitType(), -1, getOwnerINLINE()) > 0 )
							{
								continue;
							}
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/
							int iValue = (pLoopCity->getPopulation() * 4);

							if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
							{
								iValue *= 4;
							}
							else
							{
								iValue *= 3;
							}
							
							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopCity->plot();
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_SPREAD, pBestPlot);
		return true;
	}

	return false;	
}
	
// Returns true if a mission was pushed...
bool CvUnitAI::AI_discover(bool bThisTurnOnly, bool bFirstResearchOnly)
{
	TechTypes eDiscoverTech;
	bool bIsFirstTech;
	int iPercentWasted = 0;

	if (canDiscover(plot()))
	{
		eDiscoverTech = getDiscoveryTech();
		bIsFirstTech = (GET_PLAYER(getOwnerINLINE()).AI_isFirstTech(eDiscoverTech));

        if (bFirstResearchOnly && !bIsFirstTech)
        {
            return false;
        }

		iPercentWasted = (100 - ((getDiscoverResearch(eDiscoverTech) * 100) / getDiscoverResearch(NO_TECH)));
		FAssert(((iPercentWasted >= 0) && (iPercentWasted <= 100)));


        if (getDiscoverResearch(eDiscoverTech) >= GET_TEAM(getTeam()).getResearchLeft(eDiscoverTech))
        {
            if ((iPercentWasted < 51) && bFirstResearchOnly && bIsFirstTech)
            {
                getGroup()->pushMission(MISSION_DISCOVER);
                return true;
            }

            if (iPercentWasted < (bIsFirstTech ? 31 : 11))
            {
                //I need a good way to assess if the tech is actually valuable...
                //but don't have one.
                getGroup()->pushMission(MISSION_DISCOVER);
                return true;
            }
        }
        else if (bThisTurnOnly)
        {
            return false;
        }

        if (iPercentWasted <= 11)
        {
            if (GET_PLAYER(getOwnerINLINE()).getCurrentResearch() == eDiscoverTech)
            {
                getGroup()->pushMission(MISSION_DISCOVER);
                return true;
            }
        }
    }
	return false;
}


/************************************************************************************************/
/* BETTER_BTS_AI_MOD & RevDCM                     09/03/10                        jdog5000      */
/*                                                                                phungus420    */
/* Great People AI, Unit AI                                                                     */
/************************************************************************************************/
bool CvUnitAI::AI_leadLegend()
{
	PROFILE_FUNC();

	FAssertMsg(!isHuman(), "isHuman did not return false as expected");
	FAssert(NO_PLAYER != getOwnerINLINE());

	CvPlayer& kOwner = GET_PLAYER(getOwnerINLINE());

	bool bHasLegend = false;
	int iLoop;
	bool bBestUnitLegend = false;
	CvUnit* pLoopUnit = NULL;

	CvUnit* pBestUnit = NULL;
	CvPlot* pBestPlot = NULL;

	CvUnit* pBestStrUnit = NULL;
	CvPlot* pBestStrPlot = NULL;


	for (pLoopUnit = kOwner.firstUnit(&iLoop); pLoopUnit; pLoopUnit = kOwner.nextUnit(&iLoop))
	{
		if(pLoopUnit != NULL)
		{
			if (GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() >= 0
			&& GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() <= 3)
			{
				if(canLead(pLoopUnit->plot(), pLoopUnit->getID()))
				{
					bHasLegend = true;
					break;
				}
			}
		}
	}

	if (bHasLegend)
	{
		pLoopUnit = NULL;
		int iBestStrength = 0;
		int iCombatStrength;
		bool bValid;
		bool bLegend;

		for (pLoopUnit = kOwner.firstUnit(&iLoop); pLoopUnit; pLoopUnit = kOwner.nextUnit(&iLoop))
		{
			if(pLoopUnit != NULL)
			{
				bValid = false;
				bLegend = false;

				if (GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() > 0
				&& GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() < 7)
				{
					bLegend = true;

					if (canLead(pLoopUnit->plot(), pLoopUnit->getID()) > 0)
					{
						if (AI_plotValid(pLoopUnit->plot()))
						{
							if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
							{
								if( pLoopUnit->combatLimit() == 100 )
								{
									if (generatePath(pLoopUnit->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true))
									{
										// pick the unit with the highest current strength
										iCombatStrength = pLoopUnit->currCombatStr(NULL, NULL);
										iCombatStrength *= 10 + (pLoopUnit->getExperience() * 2);
										iCombatStrength /= 15;

										if(bLegend)
										{
											iCombatStrength *= 10 - GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances();
											iCombatStrength /= 3;
										}

										if (iCombatStrength > iBestStrength)
										{
											iBestStrength = iCombatStrength;
											pBestStrUnit = pLoopUnit;
											pBestStrPlot = getPathEndTurnPlot();
											if(bLegend)
											{
												bBestUnitLegend = true;
											}
											else
											{
												bBestUnitLegend = false;
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if(bBestUnitLegend && pBestStrUnit != NULL)
	{
		pBestPlot = pBestStrPlot;
		pBestUnit = pBestStrUnit;
	}
	else
	{
		return false;
	}

	if (pBestPlot)
	{
		if (atPlot(pBestPlot) && pBestUnit)
		{
			if( gUnitLogLevel > 2 )
			{
				CvWString szString;
				getUnitAIString(szString, pBestUnit->AI_getUnitAIType());

				if(bBestUnitLegend)
				{
					logBBAI("      Great general %d for %S chooses to lead %S Legend Unit", getID(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestUnit->getName(0).GetCString());
				}
				else
				{
					logBBAI("      Great general %d for %S chooses to lead %S with UNITAI %S", getID(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestUnit->getName(0).GetCString(), szString.GetCString());
				}
			}
			getGroup()->pushMission(MISSION_LEAD, pBestUnit->getID());
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
		}
	}

	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

// Returns true if a mission was pushed...
bool CvUnitAI::AI_lead(std::vector<UnitAITypes>& aeUnitAITypes)
{
	PROFILE_FUNC();

	FAssertMsg(!isHuman(), "isHuman did not return false as expected");
	FAssertMsg(AI_getUnitAIType() != NO_UNITAI, "AI_getUnitAIType() is not expected to be equal with NO_UNITAI");
	FAssert(NO_PLAYER != getOwnerINLINE());

	CvPlayer& kOwner = GET_PLAYER(getOwnerINLINE());

	bool bNeedLeader = false;
/************************************************************************************************/
/* BETTER_BTS_AI_MOD & RevDCM                     09/03/10                        jdog5000      */
/*                                                                                phungus420    */
/* Great People AI, Unit AI                                                                     */
/************************************************************************************************/
	int iLoop;
	bool bBestUnitLegend = false;
	CvUnit* pLoopUnit = NULL;

	CvUnit* pBestUnit = NULL;
	CvPlot* pBestPlot = NULL;

	// AI may use Warlords to create super-medic units
	CvUnit* pBestStrUnit = NULL;
	CvPlot* pBestStrPlot = NULL;

	CvUnit* pBestHealUnit = NULL;
	CvPlot* pBestHealPlot = NULL;

	
	for (int iI = 0; iI < MAX_CIV_TEAMS; iI++)
	{
		CvTeamAI& kLoopTeam = GET_TEAM((TeamTypes)iI);
		if (isEnemy((TeamTypes)iI))
		{
			if (kLoopTeam.countNumUnitsByArea(area()) > 0)
			{
				bNeedLeader = true;
				break;
			}
		}
	}

	if (bNeedLeader)
	{
		int iBestStrength = 0;
		int iBestHealing = 0;
		int iCombatStrength;
		bool bValid;
		bool bLegend;

		for (pLoopUnit = kOwner.firstUnit(&iLoop); pLoopUnit; pLoopUnit = kOwner.nextUnit(&iLoop))
		{
			if(pLoopUnit != NULL)
			{
				bValid = false;
				bLegend = false;

				if (GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() > 0
				&& GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances() < 7)
				{
					if (canLead(pLoopUnit->plot(), pLoopUnit->getID()) > 0)
					{
						bValid = true;
						bLegend = true;
					}
				}

				if( !bValid )
				{
					for (uint iI = 0; iI < aeUnitAITypes.size(); iI++)
					{
						if (pLoopUnit->AI_getUnitAIType() == aeUnitAITypes[iI] || NO_UNITAI == aeUnitAITypes[iI])
						{
							if (canLead(pLoopUnit->plot(), pLoopUnit->getID()) > 0)
							{
								bValid = true;
								break;
							}
						}
					}
				}

				if( bValid )
				{
					if (AI_plotValid(pLoopUnit->plot()))
					{
						if (!(pLoopUnit->plot()->isVisibleEnemyUnit(this)))
						{
							if( pLoopUnit->combatLimit() == 100 )
							{
								if (generatePath(pLoopUnit->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true))
								{
									// pick the unit with the highest current strength
									iCombatStrength = pLoopUnit->currCombatStr(NULL, NULL);
									iCombatStrength *= 10 + (pLoopUnit->getExperience() * 2);
									iCombatStrength /= 15;

									if(bLegend)
									{
										iCombatStrength *= 10 - GC.getUnitClassInfo(pLoopUnit->getUnitClassType()).getMaxGlobalInstances();
										iCombatStrength /= 3;
									}

									if (iCombatStrength > iBestStrength)
									{
										iBestStrength = iCombatStrength;
										pBestStrUnit = pLoopUnit;
										pBestStrPlot = getPathEndTurnPlot();
										if(bLegend)
										{
											bBestUnitLegend = true;
										}
										else
										{
											bBestUnitLegend = false;
										}
									}
									
									// or the unit with the best healing ability
									int iHealing = pLoopUnit->getSameTileHeal() + pLoopUnit->getAdjacentTileHeal();
									if (iHealing > iBestHealing)
									{
										iBestHealing = iHealing;
										pBestHealUnit = pLoopUnit;
										pBestHealPlot = getPathEndTurnPlot();
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if( AI_getBirthmark() % 3 == 0 && pBestHealUnit != NULL )
	{
		pBestPlot = pBestHealPlot;
		pBestUnit = pBestHealUnit;
	}
	else
	{
		pBestPlot = pBestStrPlot;
		pBestUnit = pBestStrUnit;
	}

	if (pBestPlot)
	{
		if (atPlot(pBestPlot) && pBestUnit)
		{
			if( gUnitLogLevel > 2 )
			{
				CvWString szString;
				getUnitAIString(szString, pBestUnit->AI_getUnitAIType());

				if(bBestUnitLegend)
				{
					logBBAI("      Great general %d for %S chooses to lead %S Legend Unit", getID(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestUnit->getName(0).GetCString());
				}
				else
				{
					logBBAI("      Great general %d for %S chooses to lead %S with UNITAI %S", getID(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestUnit->getName(0).GetCString(), szString.GetCString());
				}
			}
			getGroup()->pushMission(MISSION_LEAD, pBestUnit->getID());
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	return false;
}

// Returns true if a mission was pushed... 
// iMaxCounts = 1 would mean join a city if there's no existing joined GP of that type.
bool CvUnitAI::AI_join(int iMaxCount)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	SpecialistTypes eBestSpecialist;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;
	int iCount;

	iBestValue = 0;
	pBestPlot = NULL;
	eBestSpecialist = NO_SPECIALIST;
	iCount = 0;

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/03/10                                jdog5000      */
/*                                                                                phungus420    */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	if( iMaxCount && (GC.getGame().getSorenRandNum(11, "Settle GG") < iMaxCount + 5) )
	{
		return false;
	}

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		// BBAI efficiency: check same area
		if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
		{
			if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
			{
				if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
				{
					for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
					{
						bool bDoesJoin = false;
						SpecialistTypes eSpecialist = (SpecialistTypes)iI;
						if (m_pUnitInfo->getGreatPeoples(eSpecialist))
						{
							bDoesJoin = true;
						}
						if (bDoesJoin)
						{
							iCount += pLoopCity->getSpecialistCount(eSpecialist);
							if (iCount >= iMaxCount)
							{
								return false;
							}
						}
						
						if (canJoin(pLoopCity->plot(), ((SpecialistTypes)iI)))
						{
							int iTotalThreat = std::max(1, GET_PLAYER(getOwnerINLINE()).AI_getTotalAreaCityThreat(area(), NULL));
							int iOurThreat = pLoopCity->AI_cityThreat();

							//	Replaced local danger blocking of joins with more nuanced threat level evaluation.
							//	This reduces the chances of the join being blocked by local dnager counts from
							//	battles with animals and so forth
							if ( iOurThreat < (2*iTotalThreat)/GET_PLAYER(getOwnerINLINE()).getNumCities() )
							{
								iValue = pLoopCity->AI_specialistValue(((SpecialistTypes)iI), pLoopCity->AI_avoidGrowth(), false);
								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = getPathEndTurnPlot();
									eBestSpecialist = ((SpecialistTypes)iI);
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (eBestSpecialist != NO_SPECIALIST))
	{
		if (atPlot(pBestPlot))
		{
			getGroup()->pushMission(MISSION_JOIN, eBestSpecialist);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/09/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}

CvUnitAI* CvUnitAI::AI_cityConstructionTargeted(CvCity* pCity, BuildingTypes eBuilding, CvSelectionGroup* omitGroup) const
{
	PROFILE_FUNC();

	int iLoop;
	for(CvSelectionGroup* pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopSelectionGroup; pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
	{
		if ( pLoopSelectionGroup != omitGroup &&
			 pLoopSelectionGroup->AI_getMissionAIPlot() == pCity->plot() &&
			 pLoopSelectionGroup->AI_getMissionAIType() == MISSIONAI_CONSTRUCT )
		{
			CvUnitAI* targetingUnit = (CvUnitAI*)pLoopSelectionGroup->getHeadUnit();

			//	Have to handle the case of a group with no units.  This can occur after a foprce group
			//	split due to things like revokation of open borders that forces units to be unserimoniously
			//	moved to another plot (and ungroups them in doing so since it is possible that only a subset
			//	of a group has to move)
			if ( targetingUnit != NULL && targetingUnit->m_eIntendedConstructBuilding == eBuilding )
			{
				return targetingUnit;
			}
		}
	}

	return NULL;
}

//	Should we disband this unit?
bool CvUnitAI::AI_scrapSubdued()
{
	PROFILE_FUNC();

	if ( GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble() )
	{
		//	Always scrap subdued animals if we're in financial trouble and they were unable to
		//	find construction targets (which is implied by having called this)
		scrap();
		return true;
	}

	//	Count how many units of this type we have that couldn't find construction missions (by
	//	implication of getting here no further units of this type could)
	int iLoop;
	int	iSurplass = 0;
	//	Hold a suplasss of each type of up to 2 (inside our borders) or 1 (outside), boosted by 1 if we have less then 4 cities
	int	iExtra = (plot()->getOwnerINLINE() == getOwnerINLINE() ? 2 : 1) + (GET_PLAYER(getOwnerINLINE()).getNumCities() < 4 ? 1 : 0);

	for (CvUnit* pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
	{
		if ( pLoopUnit->getUnitType() == getUnitType() && pLoopUnit->getGroup()->AI_getMissionAIType() != MISSIONAI_CONSTRUCT )
		{
			iSurplass++;
		}
	}

	if ( iSurplass > iExtra )
	{
		scrap();
		return true;
	}

	return false;
}

bool CvUnitAI::AI_moveToOurTerritory(int maxMoves)
{
	int iSearchRange = AI_searchRange(maxMoves);

	for (int iDX = -iSearchRange; iDX <= iSearchRange; ++iDX)
	{
		for (int iDY = -iSearchRange; iDY <= iSearchRange; ++iDY)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL && pLoopPlot->area() == plot()->area())
			{
				if ( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() ) 
				{
					int iTurns;

					if ( generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iTurns, maxMoves) )
					{
						CvPlot* endTurnPlot = getPathEndTurnPlot();

						if ( !exposedToDanger(endTurnPlot, 75) )
						{
							return getGroup()->pushMissionInternal(MISSION_MOVE_TO, endTurnPlot->getX_INLINE(), endTurnPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY);
						}
					}
				}
			}
		}
	}

	return false;
}

//	To cope with units like heroes, that are constructed under various unitAIs, but which
//	can construct buildings as an option, this rouine determines whether a switch to doing
//	so is appropriate, and if so performs it
bool CvUnitAI::checkSwitchToConstruct(void)
{
	//	Don't bail on a city for which we are the only defender
	if ( plot()->getPlotCity() != NULL && plot()->getNumDefenders(getOwnerINLINE()) == 1 )
	{
		return false;
	}

	if ( m_pUnitInfo->getHasBuildings() )
	{
		CvPlot*	pBestConstructPlot;
		CvPlot*	pBestPlot;
		CvUnitAI* eBestTargetingUnit;
		BuildingTypes eBestBuilding;

		//	What are the relative values of the possible constructed buildings vs
		//	our military value
		int iConstructValue = getBestConstructValue(MAX_INT, MAX_INT, 0, 0, true, pBestConstructPlot, pBestPlot, eBestTargetingUnit, eBestBuilding);
		int iMilitaryValue = GET_PLAYER(getOwnerINLINE()).AI_unitValue(m_eUnitType, AI_getUnitAIType(), area());

		if ( iConstructValue > iMilitaryValue )
		{
			//	If we are grouped must ungroup before enacting this
			if ( getGroup()->getNumUnits() > 1 )
			{
				joinGroup(NULL);
			}

			return enactConstruct(pBestConstructPlot, pBestPlot, eBestTargetingUnit, eBestBuilding);
		}
		else
		{
			//	If this is a bit out-dated as a military unit consider joining a city as a specialist
			UnitTypes eBestUnit = GET_PLAYER(getOwnerINLINE()).bestBuildableUnitForAIType(getDomainType(), AI_getUnitAIType());
			if ( eBestUnit != NO_UNIT )
			{
				int	iBestUnitAIValue = GET_PLAYER(getOwnerINLINE()).AI_unitValue(eBestUnit, AI_getUnitAIType(), GET_PLAYER(getOwnerINLINE()).getCapitalCity()->area());

				if ( iBestUnitAIValue > (3*iMilitaryValue)/2 )
				{
					return AI_join();
				}
			}

			return false;
		}
	}

	// AIAndy: Return value was missing here, unit can't construct buildings so return false
	return false;
}

bool CvUnitAI::enactConstruct(CvPlot* pBestConstructPlot, CvPlot* pBestPlot, CvUnitAI* eBestTargetingUnit, BuildingTypes eBestBuilding)
{
	if ((pBestPlot != NULL) && (pBestConstructPlot != NULL) && (eBestBuilding != NO_BUILDING))
	{
		GET_PLAYER(getOwnerINLINE()).AI_changeNumBuildingsNeeded(eBestBuilding, -1);

		if (atPlot(pBestConstructPlot))
		{
			getGroup()->pushMission(MISSION_CONSTRUCT, eBestBuilding);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));

			//	Take over responsibility from any overridden targeting unit
			if ( eBestTargetingUnit != NULL )
			{
				eBestTargetingUnit->m_eIntendedConstructBuilding = NO_BUILDING;
			}

			m_eIntendedConstructBuilding = eBestBuilding;

			//	If we have to move outside our own territory heal first
			if ( getDamage() > 0 && pBestPlot->getOwnerINLINE() != getOwnerINLINE())
			{
				//	Set the mission AI up as construct because that is our actual intention (once healed)
				getGroup()->pushMission(MISSION_HEAL, -1, -1, 0, false, false, MISSIONAI_CONSTRUCT, pBestConstructPlot);
				return true;
			}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/09/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY | MOVE_WITH_CAUTION | MOVE_AVOID_ENEMY_UNITS, false, false, MISSIONAI_CONSTRUCT, pBestConstructPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}

int CvUnitAI::getBestConstructValue(int iMaxCount, int iMaxSingleBuildingCount, int iDecayProbabilityRate, int iThreshold, bool assumeSameValueEverywhere, CvPlot*& pBestConstructPlot, CvPlot*& pBestPlot, CvUnitAI*& eBestTargetingUnit, BuildingTypes& eBestBuilding)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	int iValue;
	int iBestValue;
	int iBestWeightedValue;
	int iLoop;
	int iI;
	int iCount;
	int iContructRand = 100;
	int iConstructBelow = 100;

	if ( iDecayProbabilityRate != 0 )
	{
		iContructRand = GC.getGame().getSorenRandNum(100, "AI construction probability");
	}

	iBestValue = 0;
	iBestWeightedValue = 0;
	eBestBuilding = NO_BUILDING;
	pBestConstructPlot = NULL;
	pBestPlot = NULL;
	eBestTargetingUnit = NULL;
	
	//	If we already has a chosen construction targeted then start with a presumption
	//	we'll stick to it unless something significantly better is found
	if ( m_eIntendedConstructBuilding != NO_BUILDING && getGroup()->AI_getMissionAIType() == MISSIONAI_CONSTRUCT )
	{
		pLoopCity = getGroup()->AI_getMissionAIPlot()->getPlotCity();

		if ( pLoopCity != NULL &&
			 canConstruct(pLoopCity->plot(), m_eIntendedConstructBuilding) &&
			 generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true) )
		{
			iBestValue = (pLoopCity->AI_buildingValue(m_eIntendedConstructBuilding)*110)/100;
			pBestPlot = getPathEndTurnPlot();
			pBestConstructPlot = pLoopCity->plot();
			eBestBuilding = m_eIntendedConstructBuilding;
		}
	}

	std::map<BuildingTypes,int>	possibleBuildings;

	for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
	{
		BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);

		if (NO_BUILDING != eBuilding)
		{
			if ((m_pUnitInfo->getForceBuildings(eBuilding) || m_pUnitInfo->getBuildings(eBuilding)) && GET_PLAYER(getOwnerINLINE()).canConstruct(eBuilding,false,false,true))
			{
				if (GET_PLAYER(getOwnerINLINE()).AI_getNumBuildingsNeeded(eBuilding, (getDomainType() == DOMAIN_SEA)) > 0)
				{
					int iThisConstructBelow = iConstructBelow;
					iCount = 0;

					for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
					{
						if (pLoopCity->getNumBuilding(eBuilding) > 0)
						{
							iCount++;

							if (iCount >= iMaxCount || iThisConstructBelow < iContructRand)
							{
								break;
							}

							//	If we are deacying the construct probability based on existing building count...
							if ( iDecayProbabilityRate != 0 )
							{
								iThisConstructBelow = (iThisConstructBelow*iDecayProbabilityRate)/100;
							}
						}
					}

					if ( pLoopCity == NULL )
					{
						possibleBuildings[eBuilding] = 0;
					}
				}
			}
		}
	}

	if ( possibleBuildings.size() == 0 )
	{
		return 0;
	}

	CvReachablePlotSet	plotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, MAX_INT);

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		//if (AI_plotValid(pLoopCity->plot()) && pLoopCity->area() == area())
		if (plotSet.find(pLoopCity->plot()) != plotSet.end())
		{
			for(std::map<BuildingTypes,int>::iterator itr = possibleBuildings.begin(); itr != possibleBuildings.end(); ++itr)
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))	//	Koshling - this line is questionable
				{
					//	Check some other unit hasn't already got this city targeted to construct this building
					CvUnitAI*	targetingUnit = AI_cityConstructionTargeted(pLoopCity, itr->first, getGroup());
					bool bValid;

					//	If we're a better choice due to being already inside our own territory
					if ( targetingUnit != NULL &&
						 targetingUnit->plot()->getOwnerINLINE() != getOwnerINLINE() &&
						 plot()->getOwnerINLINE() == getOwnerINLINE() &&
						 generatePath(pLoopCity->plot(), MOVE_OUR_TERRITORY, true))
					{
						bValid = true;
					}
					else
					{
						bValid = (targetingUnit == NULL);
					}

					if ( bValid )
					{
						PROFILE("CvUnitAI::getBestConstructValue.Valuation");

						if (GET_PLAYER(getOwnerINLINE()).getBuildingClassCount((BuildingClassTypes)GC.getBuildingInfo(itr->first).getBuildingClassType()) < iMaxSingleBuildingCount)
						{
							if (canConstruct(pLoopCity->plot(), itr->first))
							{
								PROFILE("CvUnitAI::getBestConstructValue.Pathing");

								int iPathTurns;

								if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
								{
									//	When evaluating whether a hero unit should instead go and produce a building
									//	we want to avoid expensive calculations for every city, when in practise the kinds
									//	of things heroes can build have global effects and thus basically the same value
									//	everywhere that they have any value (note that this is a heuristic assumption that is true CURRENTLY,
									//	but may need to be revisited)
									//	Koshling - also extended this to subdued animals for performance reasons - generally for all cities
									//	and animal buiding CAN be built in this will be a good approximation
									if ( assumeSameValueEverywhere && itr->second > 0 )
									{
										iValue = itr->second;
									}
									else
									{
										iValue = pLoopCity->AI_buildingValue(itr->first);

										itr->second = iValue;
									}

									//	Weight by ease of reaching and population slightly in the case of same-everywhere asserted
									//	builds
									int iWeightedValue = (iValue*5)/(4 + iPathTurns);
									
									if ( assumeSameValueEverywhere )
									{
										iWeightedValue = (iWeightedValue*(5+pLoopCity->getPopulation()))/10;
									}
									else
									{
										iWeightedValue = iValue;
									}

									if ((iValue > iThreshold) && (iWeightedValue > iBestWeightedValue))
									{
										iBestValue = iValue;
										iBestWeightedValue = iWeightedValue;
										pBestPlot = getPathEndTurnPlot();
										pBestConstructPlot = pLoopCity->plot();
										eBestBuilding = itr->first;
										eBestTargetingUnit = targetingUnit;
									}
								}
							}
						}
						else
						{
							break;
						}
					}
				}
			}
		}
	}

	return iBestValue;
}

// Returns true if a mission was pushed... 
// iMaxCount = 1 would mean construct only if there are no existing buildings 
//   constructed by this GP type.
bool CvUnitAI::AI_construct(int iMaxCount, int iMaxSingleBuildingCount, int iThreshold, bool bDecayProbabilities, bool assumeSameValueEverywhere)
{
	PROFILE_FUNC();

	CvPlot* pBestPlot;
	CvPlot* pBestConstructPlot;
	CvUnitAI* eBestTargetingUnit;
	BuildingTypes eBestBuilding;

	if ( !m_pUnitInfo->getHasBuildings() )
	{
		return false;
	}

	if (getBestConstructValue(iMaxCount, iMaxSingleBuildingCount, bDecayProbabilities ? 50 : 0, iThreshold, assumeSameValueEverywhere, pBestConstructPlot, pBestPlot, eBestTargetingUnit, eBestBuilding) > 0)
	{
		if( gUnitLogLevel >= 2 )
		{
			logBBAI("    %S at (%d,%d) going to construct %S at (%d,%d)", getName(0).GetCString(), plot()->getX_INLINE(), plot()->getY_INLINE(), GC.getBuildingInfo(eBestBuilding).getDescription(), pBestConstructPlot->getX_INLINE(), pBestConstructPlot->getY_INLINE());
		}

		return enactConstruct(pBestConstructPlot, pBestPlot, eBestTargetingUnit, eBestBuilding);
	}
	else
	{
		return false;
	}
}

// Returns true if a mission was pushed... 
// Try to get the best outcome mission done
bool CvUnitAI::AI_outcomeMission()
{
	PROFILE_FUNC();

	CvPlot* pBestPlot = NULL;
	CvPlot* pBestMissionPlot = NULL;
	MissionTypes eBestMission = NO_MISSION;
	int iBestValue = 0;

	// favor the closest city
	CvCity* pClosestCity = plot()->getPlotCity();
	if (!pClosestCity)
		pClosestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE(), NO_TEAM, true, false);

	std::vector<std::pair<MissionTypes, CvOutcomeList*> > aMissions;

	CvUnitInfo& kInfo = getUnitInfo();

	for (int iI = 0; iI < kInfo.getNumActionOutcomes(); iI++)
	{
		aMissions.push_back(std::make_pair(kInfo.getActionOutcomeMission(iI), kInfo.getActionOutcomeList(iI)));
	}

	// check the unit combat types for outcome missions
	for (int iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
	{
		if (hasCombatType((UnitCombatTypes)iI))
		{
			CvUnitCombatInfo& kCombatInfo = GC.getUnitCombatInfo((UnitCombatTypes)iI);
			for (int iI = 0; iI < kCombatInfo.getNumActionOutcomes(); iI++)
			{
				aMissions.push_back(std::make_pair(kCombatInfo.getActionOutcomeMission(iI), kCombatInfo.getActionOutcomeList(iI)));
			}
		}
	}

	CvReachablePlotSet	plotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, MAX_INT);

	for (std::vector<std::pair<MissionTypes, CvOutcomeList*> >::iterator it = aMissions.begin(); it != aMissions.end(); ++it)
	{
		MissionTypes eMission = it->first;
		CvOutcomeList* pOutcomeList = it->second;

		if (eMission != NO_MISSION)
		{
			if (pOutcomeList->isPossibleSomewhere(*this))
			{
				if (pClosestCity)
				{
					int iLoop;
					for (CvCity* pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
					{					
						//if (pLoopCity->area() == area())
						if (plotSet.find(pLoopCity->plot()) != plotSet.end())
						{
							if (pOutcomeList->isPossibleInPlot(*this, *(pLoopCity->plot())))
							{
								int iValue = pOutcomeList->AI_getValueInPlot(*this, *(pLoopCity->plot()));
								if (iValue > iBestValue)
								{
									if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true))
									{
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
										pBestMissionPlot = pLoopCity->plot();
										eBestMission = eMission;
									}
								}
							}
						}
					}
				}
				else
				{
					// There is no city in this area, so try to execute an outcome mission at the current location
					if (pOutcomeList->isPossibleInPlot(*this, *(plot())))
					{
						int iValue = pOutcomeList->AI_getValueInPlot(*this, *(plot()));
						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = getPathEndTurnPlot();
							pBestMissionPlot = plot();
							eBestMission = eMission;
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestMissionPlot != NULL) && (eBestMission != NO_MISSION))
	{
		if( gUnitLogLevel >= 2 )
		{
			logBBAI("    %S at (%d,%d) going to enact mission %S at (%d,%d)", getName(0).GetCString(), plot()->getX_INLINE(), plot()->getY_INLINE(), GC.getMissionInfo(eBestMission).getDescription(), pBestMissionPlot->getX_INLINE(), pBestMissionPlot->getY_INLINE());
		}

		if (atPlot(pBestMissionPlot))
		{
			getGroup()->pushMission(eBestMission);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));

			//	If we have to move outside our own territory heal first
			if ( getDamage() > 0 && pBestPlot->getOwnerINLINE() != getOwnerINLINE())
			{
				//	Set the mission AI up as construct because that is our actual intention (once healed)
				getGroup()->pushMission(MISSION_HEAL, -1, -1, 0, false, false, NO_MISSIONAI, pBestMissionPlot);
				return true;
			}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/09/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY | MOVE_WITH_CAUTION | MOVE_AVOID_ENEMY_UNITS, false, false, NO_MISSIONAI, pBestMissionPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_switchHurry()
{
	PROFILE_FUNC();

	CvCity* pCity;
	BuildingTypes eBestBuilding;
	int iValue;
	int iBestValue;
	int iI;

	pCity = plot()->getPlotCity();

	if ((pCity == NULL) || (pCity->getOwnerINLINE() != getOwnerINLINE()))
	{
		return false;
	}

	iBestValue = 0;
	eBestBuilding = NO_BUILDING;

	for (iI = 0; iI < GC.getNumBuildingClassInfos(); iI++)
	{
		if (isWorldWonderClass((BuildingClassTypes)iI))
		{
			BuildingTypes eBuilding = (BuildingTypes)GC.getCivilizationInfo(getCivilizationType()).getCivilizationBuildings(iI);

			if (NO_BUILDING != eBuilding)
			{
				if (pCity->canConstruct(eBuilding))
				{
					if (pCity->getBuildingProduction(eBuilding) == 0)
					{
						if (getMaxHurryProduction(pCity) >= pCity->getProductionNeeded(eBuilding))
						{
							iValue = pCity->AI_buildingValue(eBuilding);

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								eBestBuilding = eBuilding;
							}
						}
					}
				}
			}
		}
	}

	if (eBestBuilding != NO_BUILDING)
	{
		pCity->pushOrder(ORDER_CONSTRUCT, eBestBuilding, -1, false, false, false);

		if (pCity->getProductionBuilding() == eBestBuilding)
		{
			if (canHurry(plot()))
			{
				getGroup()->pushMission(MISSION_HURRY);
				return true;
			}
		}

		FAssert(false);
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_hurry(bool bAny)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestHurryPlot;
	bool bHurry;
	int iTurnsLeft;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestHurryPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
		// BBAI efficiency: check same area
		if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		{
			if ( canHurry(pLoopCity->plot()))
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
					if (bAny || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_HURRY, getGroup()) == 0)
					{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/03/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
						if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
						{
							bHurry = false;

							if (pLoopCity->isProductionBuilding())
							{
								if (bAny || isWorldWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pLoopCity->getProductionBuilding()).getBuildingClassType())))
								{
									bHurry = true;
								}
							}

							if (bHurry)
							{
								iTurnsLeft = pLoopCity->getProductionTurnsLeft();

								iTurnsLeft -= iPathTurns;

								if (iTurnsLeft > (bAny ? 1 : 8))
								{
									iValue = iTurnsLeft;

									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
										pBestHurryPlot = pLoopCity->plot();
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestHurryPlot != NULL))
	{
		if (atPlot(pBestHurryPlot))
		{
			getGroup()->pushMission(MISSION_HURRY);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/09/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_HURRY, pBestHurryPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}

/************************************************************************************************/
/* RevDCM                  Start		 5/2/09                                                 */
/*                                                                                              */
/* Inquisitions                                                                                 */
/************************************************************************************************/
bool CvUnitAI::AI_doInquisition()
{
	if (AI_moveToInquisitionTarget())
	{
		return true;
	}
	return performInquisition();
}
bool CvUnitAI::AI_moveToInquisitionTarget()
{
	CvCity* pTargetCity = NULL;

	pTargetCity = GET_PLAYER(getOwnerINLINE()).getInquisitionRevoltCity(this, false, GC.getDefineINT("OC_MIN_REV_INDEX"), 0);
	if(pTargetCity == NULL)
	{
		pTargetCity = GET_PLAYER(getOwnerINLINE()).getTeamInquisitionRevoltCity(this, false, GC.getDefineINT("OC_MIN_REV_INDEX"), 0);
		if(pTargetCity == NULL)
		{
			pTargetCity = GET_PLAYER(getOwnerINLINE()).getReligiousVictoryTarget(this, false);
		}
	}
	
	if (pTargetCity != NULL)
	{
		if (generatePath(pTargetCity->plot()))
		{
			if (!atPlot(pTargetCity->plot()))
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pTargetCity->getX(), pTargetCity->getY(), MOVE_NO_ENEMY_TERRITORY, false, true, MISSIONAI_INQUISITION, pTargetCity->plot());
			}
		}
	}
	return false;
}
/************************************************************************************************/
/* Inquisitions	                     END                                                        */
/************************************************************************************************/


// Returns true if a mission was pushed...
bool CvUnitAI::AI_greatWork()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestGreatWorkPlot;
	int iValue;
	int iBestValue;
	int iLoop;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestGreatWorkPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
		// BBAI efficiency: check same area
		if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		{
			if (canGreatWork(pLoopCity->plot()))
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_GREAT_WORK, getGroup()) == 0)
					{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      04/03/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
						if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
						{
							iValue = pLoopCity->AI_calculateCulturePressure(true);
							iValue -= ((100 * pLoopCity->getCulture(pLoopCity->getOwnerINLINE())) / std::max(1, getGreatWorkCulture(pLoopCity->plot())));
							if (iValue > 0)
							{
								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = getPathEndTurnPlot();
									pBestGreatWorkPlot = pLoopCity->plot();
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestGreatWorkPlot != NULL))
	{
		if (atPlot(pBestGreatWorkPlot))
		{
			getGroup()->pushMission(MISSION_GREAT_WORK);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/09/09                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_GREAT_WORK, pBestGreatWorkPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_offensiveAirlift()
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pTargetCity;
	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iLoop;

	if (getGroup()->getNumUnits() > 1)
	{
		return false;
	}

	if (area()->getTargetCity(getOwnerINLINE()) != NULL)
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getMaxAirlift() == 0)
	{
		return false;
	}

	iBestValue = 0;
	pBestPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (pLoopCity->area() != pCity->area())
		{
			if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
			{
				pTargetCity = pLoopCity->area()->getTargetCity(getOwnerINLINE());

				if (pTargetCity != NULL)
				{
					AreaAITypes eAreaAIType = pTargetCity->area()->getAreaAIType(getTeam());
					if (((eAreaAIType == AREAAI_OFFENSIVE) || (eAreaAIType == AREAAI_DEFENSIVE) || (eAreaAIType == AREAAI_MASSING))
						|| pTargetCity->AI_isDanger())
					{
						iValue = 10000;

						iValue *= (GET_PLAYER(getOwnerINLINE()).AI_militaryWeight(pLoopCity->area()) + 10);
						iValue /= (GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), AI_getUnitAIType()) + 10);

						iValue += std::max(1, ((GC.getMapINLINE().maxStepDistance() * 2) - GC.getMapINLINE().calculatePathDistance(pLoopCity->plot(), pTargetCity->plot())));
						
						if (AI_getUnitAIType() == UNITAI_PARADROP)
						{
							CvCity* pNearestEnemyCity = GC.getMapINLINE().findCity(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), NO_PLAYER, NO_TEAM, false, false, getTeam());

							if (pNearestEnemyCity != NULL)
							{
								int iDistance = plotDistance(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), pNearestEnemyCity->getX_INLINE(), pNearestEnemyCity->getY_INLINE());
								if (iDistance <= getDropRange())
								{
									iValue *= 5;
								}
							}
						}

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopCity->plot();
							FAssert(pLoopCity != pCity);
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_paradrop(int iRange)
{
	PROFILE_FUNC();

	if (getGroup()->getNumUnits() > 1)
	{
		return false;
	}

	CvPlot* pPlot = plot();

	if (!canParadrop(pPlot))
	{
		return false;
	}

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	int iParatrooperCount = plot()->plotCount(PUF_isParadrop, -1, -1, getOwnerINLINE());
	FAssert(iParatrooperCount > 0);

	int iSearchRange = AI_searchRange(iRange);

	for (int iDX = -iSearchRange; iDX <= iSearchRange; ++iDX)
	{
		for (int iDY = -iSearchRange; iDY <= iSearchRange; ++iDY)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
				{
					if (canParadropAt(pPlot, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						int iValue = 0;

						PlayerTypes eTargetPlayer = pLoopPlot->getOwnerINLINE();
						FAssert(NO_PLAYER != eTargetPlayer);
/************************************************************************************************/
/* UNOFFICIAL_PATCH                       08/01/08                                jdog5000      */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
/* original BTS code
						if (NO_BONUS != pLoopPlot->getBonusType())
						{
							iValue += GET_PLAYER(eTargetPlayer).AI_bonusVal(pLoopPlot->getBonusType()) - 10;
						}
*/
						// Bonus values for bonuses the AI has are less than 10 for non-strategic resources... since this is
						// in the AI territory they probably have it
						if (NO_BONUS != pLoopPlot->getNonObsoleteBonusType(getTeam()))
						{
							iValue += std::max(1,GET_PLAYER(eTargetPlayer).AI_bonusVal(pLoopPlot->getBonusType()) - 10);
						}
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/

						for (int i = -1; i <= 1; ++i)
						{
							for (int j = -1; j <= 1; ++j)
							{
								CvPlot* pAdjacentPlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), i, j);
								if (NULL != pAdjacentPlot)
								{
									CvCity* pAdjacentCity = pAdjacentPlot->getPlotCity();

									if (NULL != pAdjacentCity)
									{
										if (pAdjacentCity->getOwnerINLINE() == eTargetPlayer)
										{
											int iAttackerCount = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pAdjacentPlot, true);
											int iDefenderCount = pAdjacentPlot->getNumVisibleEnemyDefenders(this);
											iValue += 20 * (AI_attackOdds(pAdjacentPlot, true) - ((50 * iDefenderCount) / (iParatrooperCount + iAttackerCount)));
										}
									}
								}
							}
						}
						
						if (iValue > 0)
						{
							iValue += pLoopPlot->defenseModifier(getTeam(), ignoreBuildingDefense());

							CvUnit* pInterceptor = bestInterceptor(pLoopPlot);
							if (NULL != pInterceptor)
							{
								int iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();

								iInterceptProb *= std::max(0, (100 - evasionProbability()));
								iInterceptProb /= 100;

								iValue *= std::max(0, 100 - iInterceptProb / 2);
								iValue /= 100;
							}
						}

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;

							FAssert(pBestPlot != pPlot);
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_PARADROP, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}

	return false;
}


/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      09/01/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
// Returns true if a mission was pushed...
bool CvUnitAI::AI_protect(int iOddsThreshold, int iMaxPathTurns)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;

	iBestValue = 0;
	pBestPlot = NULL;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, AI_searchRange(iMaxPathTurns));

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	int iI;
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
		{
			//	Koshling - AI_plotValid() call not needed when using a CvReachablePlotSet
			if (/*AI_plotValid(pLoopPlot) &&*/ pLoopPlot->area() == area())
			{
				if (pLoopPlot->isVisible(getTeam(),false) && pLoopPlot->isVisibleEnemyUnit(this))
				{		
					if (!atPlot(pLoopPlot)) 
					{
						// BBAI efficiency: Check area for land units
						if( (getDomainType() != DOMAIN_LAND) || (pLoopPlot->area() == area()) || getGroup()->canMoveAllTerrain() )
						{
							// BBAI efficiency: Most of the time, path will exist and odds will be checked anyway.  When path doesn't exist, checking path
							// takes longer.  Therefore, check odds first.
							iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

							if ((iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold)) && (iValue*50 > iBestValue))
							{
								int iPathTurns;
								if( generatePath(pLoopPlot, 0, true, &iPathTurns, iMaxPathTurns) )
								{
									// BBAI TODO: Other units targeting this already (if path turns > 1 or 0)?
									iValue *= 100;

									iValue /= (2 + iPathTurns);
								
									if (iValue > iBestValue)
									{
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( !exposedToDanger(endTurnPlot, 100 - (100-iOddsThreshold)/2) )
										{
											iBestValue = iValue;
											pBestPlot = endTurnPlot;
											FAssert(!atPlot(pBestPlot));
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

//	This rotuine effectively parallel the test in CvCityAI for building see attack/reserve units
//	in response to a sea invader in the same sea area (but not necessarily local)
bool CvUnitAI::AI_seaAreaAttack()
{
	PROFILE_FUNC();
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot = NULL;
	int	iBestValue = 0;
	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());

	CvReachablePlotSet plotSet(getGroup(), 0);
	
	{
		PROFILE("CvUnitAI::AI_seaAreaAttack.Populate");

		plotSet.Populate(15);
	}

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
		if ((pLoopPlot->area() == area()) && pLoopPlot->isVisible(getTeam(), false) && pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
		{
			int iCount = pLoopPlot->plotCount(PUF_isEnemy, getOwnerINLINE(), 0, NO_PLAYER, NO_TEAM, PUF_isVisible, getOwnerINLINE());

			//	Refine this so that not EVERY unit heads for the same enemy incursion!
			if ( iCount > 0 )
			{
				int iNavyAlreadyPresent = kPlayer.AI_countNumLocalNavy(pLoopPlot,4);
				int iValue = (10000 + GC.getGame().getSorenRandNum(5000, "AI sea area attack"))/(2+iNavyAlreadyPresent);
				int iPathTurns;
				int iMaxPathTurns = (iBestValue == 0 ? MAX_INT : iValue/iBestValue);

				PROFILE("CvUnitAI::AI_seaAreaAttack.Pathing");
				if ( generatePath(pLoopPlot, 0, true, &iPathTurns, iMaxPathTurns) )
				{
					PROFILE("CvUnitAI::AI_seaAreaAttack.Pathed");
					iValue = iValue/(1+iPathTurns);

					if ( iValue > iBestValue )
					{
						CvPlot* endTurnPlot = getPathEndTurnPlot();

						if ( !exposedToDanger(endTurnPlot, 60) )
						{
							iBestValue = iValue;
							pBestPlot = endTurnPlot;
						}
					}
				}
			}
		}
	}

	if ( pBestPlot != NULL )
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_patrol()
{
	PROFILE_FUNC();

	CvPlot* pAdjacentPlot;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	pBestPlot = NULL;

	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));

		if (pAdjacentPlot != NULL)
		{
			if (AI_plotValid(pAdjacentPlot))
			{
				if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
				{
					if (getGroup()->canMoveInto(pAdjacentPlot,false))
					//if (generatePath(pAdjacentPlot, 0, true))
					{
/*************************************************************************************************/
/**	Xienwolf Tweak							12/13/08											**/
/**																								**/
/**					Reduction in massive Random Spam in Logger files by using Map				**/
/*************************************************************************************************/
/**								---- Start Original Code ----									**
						iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Patrol"));
/**								----  End Original Code  ----									**/
						iValue = (1 + GC.getGameINLINE().getMapRandNum(10000, "AI Patrol"));
/*************************************************************************************************/
/**	Tweak									END													**/
/*************************************************************************************************/

						if (isBarbarian())
						{
							if (!(pAdjacentPlot->isOwned()))
							{
								iValue += 20000;
							}

							if (!(pAdjacentPlot->isAdjacentOwned()))
							{
								iValue += 10000;
							}
						}
						else
						{
							if (pAdjacentPlot->isRevealedGoody(getTeam()))
							{
								iValue += 100000;
							}

							if (pAdjacentPlot->getOwnerINLINE() == getOwnerINLINE())
							{
								iValue += 10000;
							}
						}

						if (iValue > iBestValue && !exposedToDanger(pAdjacentPlot, 60))
						{
							iBestValue = iValue;
							pBestPlot = pAdjacentPlot;//getPathEndTurnPlot();
							//FAssert(!atPlot(pBestPlot));
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_defend()
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	if (AI_defendPlot(plot()))
	{
		getGroup()->pushMission(MISSION_SKIP);
		return true;
	}

	iSearchRange = AI_searchRange(1);

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot))
				{
					if (AI_defendPlot(pLoopPlot))
					{
						if (!(pLoopPlot->isVisibleEnemyUnit(this)))
						{
							if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns, 1))
							{
								iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Defend"));

								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = pLoopPlot;
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      12/06/08                                jdog5000      */
/*                                                                                              */
/* Unit AI                                                                                      */
/************************************************************************************************/
		if( !(pBestPlot->isCity()) && (getGroup()->getNumUnits() > 1) )
		{
			getGroup()->AI_makeForceSeparate();
		}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_safety(int iRange)
{
	PROFILE_FUNC();

	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvUnit* pHeadUnit;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iCount;
	int iPass;
	//int iDX, iDY;

	iSearchRange = AI_searchRange(iRange);

	iBestValue = 0;
	pBestPlot = NULL;

	bool bAnimalDanger = GET_PLAYER(getOwnerINLINE()).AI_getVisiblePlotDanger(plot(),1,true);

	iBestValue = 0;
	pBestPlot = NULL;

	int iImpassableCount = GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType());

	for (iPass = 0; iPass < 2 && pBestPlot == NULL; iPass++)
	{
#ifdef USE_REACHABLE_ENUMERATION
		CvReachablePlotSet plotSet(getGroup(), (iPass > 0) ? MOVE_IGNORE_DANGER : 0, iSearchRange);

		for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
		{
			pLoopPlot = itr.plot();
#else
		for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
		{
			for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
			{
				pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
#endif

				if (pLoopPlot != NULL)
				{
					//if (AI_plotValid(pLoopPlot))
					{
						if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
						{
							if (generatePath(pLoopPlot, ((iPass > 0) ? MOVE_IGNORE_DANGER : 0), true, &iPathTurns, iRange))
							{
								iCount = 0;

								pUnitNode = pLoopPlot->headUnitNode();

								while (pUnitNode != NULL)
								{
									pLoopUnit = ::getUnit(pUnitNode->m_data);
									pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);

									if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
									{
										if (pLoopUnit->canDefend())
										{
											pHeadUnit = pLoopUnit->getGroup()->getHeadUnit();
											FAssert(pHeadUnit != NULL);
											FAssert(getGroup()->getHeadUnit() == this);

											if (pHeadUnit != this)
											{
												if (pHeadUnit->isWaiting() || !(pHeadUnit->canMove()))
												{
													FAssert(pLoopUnit != this);
													FAssert(pHeadUnit != getGroup()->getHeadUnit());
													iCount++;
												}
											}
										}
									}
								}

								iValue = (iCount * 100);

								//	If the current danger includes animals then simply running to
								//	our borders is defense to at least the animal component of the current danger
								if ( bAnimalDanger )
								{
									if ( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() )
									{
										iValue += 75;
									}
									else if ( pLoopPlot->getOwnerINLINE() != NO_PLAYER && !atWar(pLoopPlot->getTeam(), getTeam()) )
									{
										iValue += 50;
									}
								}

								iValue += pLoopPlot->defenseModifier(getTeam(), false);

								if (atPlot(pLoopPlot))
								{
									iValue += 50;
								}
								else
								{
									iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Safety");
								}

								int iTerrainDamage = pLoopPlot->getTerrainTurnDamage(getGroup()) +
													 pLoopPlot->getFeatureTurnDamage();

								if ( iTerrainDamage > 0 )
								{
									iValue *= std::max(1,100 - getDamage() - iTerrainDamage);
									iValue /= 200;
								}

								iValue = (iValue*5)/(iPathTurns+4);

								if (iValue > iBestValue)
								{
									if ( GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pLoopPlot,1) )
									{
										iValue /= 2;
									}
									if ( iValue > iBestValue )
									{
										//	If we have to pass through worse danger to get there it's not worth it
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( endTurnPlot == pLoopPlot ||
											 !GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(endTurnPlot,1) ||
											 endTurnPlot->defenseModifier(getTeam(), false) >= plot()->defenseModifier(getTeam(), false) )
										{
											iBestValue = iValue;
											pBestPlot = pLoopPlot;
										}
									}
								}
							}
						}
					}
				}
#ifndef USE_REACHABLE_ENUMERATION
			}
#endif
		}
	}

	if (pBestPlot != NULL)
	{
		if (atPlot(pBestPlot))
		{
			OutputDebugString(CvString::format("%S (%d) seeking safety stays put at (%d,%d)...\n",getDescription().c_str(),m_iID,m_iX,m_iY).c_str());
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
		else
		{
			OutputDebugString(CvString::format("%S (%d) seeking safety moves to (%d,%d)\n",getDescription().c_str(),m_iID, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE()).c_str());
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((iPass > 0) ? MOVE_IGNORE_DANGER : 0));
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_hide()
{
	PROFILE_FUNC();

	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvUnit* pHeadUnit;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	bool bValid;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iCount;
	int iDX, iDY;
	int iI;

	if (getInvisibleType() == NO_INVISIBLE)
	{
		return false;
	}

	iSearchRange = AI_searchRange(1);

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot))
				{
					bValid = true;

					for (iI = 0; iI < MAX_TEAMS; iI++)
					{
						if (GET_TEAM((TeamTypes)iI).isAlive())
						{
							if (pLoopPlot->isInvisibleVisible(((TeamTypes)iI), getInvisibleType()))
							{
								bValid = false;
								break;
							}
						}
					}

					if (bValid)
					{
						if (!(pLoopPlot->isVisibleEnemyUnit(this)))
						{
							if (generatePath(pLoopPlot, 0, true, &iPathTurns, 1))
							{
								iCount = 1;

								pUnitNode = pLoopPlot->headUnitNode();

								while (pUnitNode != NULL)
								{
									pLoopUnit = ::getUnit(pUnitNode->m_data);
									pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);

									if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
									{
										if (pLoopUnit->canDefend())
										{
											pHeadUnit = pLoopUnit->getGroup()->getHeadUnit();
											FAssert(pHeadUnit != NULL);
											FAssert(getGroup()->getHeadUnit() == this);

											if (pHeadUnit != this)
											{
												if (pHeadUnit->isWaiting() || !(pHeadUnit->canMove()))
												{
													FAssert(pLoopUnit != this);
													FAssert(pHeadUnit != getGroup()->getHeadUnit());
													iCount++;
												}
											}
										}
									}
								}

								iValue = (iCount * 100);

								iValue += pLoopPlot->defenseModifier(getTeam(), false);

								if (atPlot(pLoopPlot))
								{
									iValue += 50;
								}
								else
								{
									iValue += GC.getGameINLINE().getSorenRandNum(50, "AI Hide");
								}

								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = pLoopPlot;
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		if (atPlot(pBestPlot))
		{
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
		else
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_goody(int iRange)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
//	CvPlot* pAdjacentPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	//int iDX, iDY;
//	int iI;

	if (isBarbarian())
	{
		return false;
	}

	FAssert(canMove());

	iSearchRange = AI_searchRange(iRange);

	iBestValue = 0;
	pBestPlot = NULL;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, iSearchRange);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot))
				{
#endif
					if (pLoopPlot->isRevealedGoody(getTeam()))
					{
						if ((!canAttack() && !pLoopPlot->isVisibleEnemyUnit(this)) || !exposedToDanger(pLoopPlot, 60))
						{
							if (!atPlot(pLoopPlot) && generatePath(pLoopPlot, 0, true, &iPathTurns, iRange))
							{
								if (iPathTurns <= iRange)
								{
									iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Goody"));

									iValue /= (iPathTurns + 1);

									if (iValue > iBestValue)
									{
										//	Does this proposed move leave us exposed at the end of this
										//	turn?
										if ( exposedToDanger(getPathEndTurnPlot(), 60) )
										{
											//	Reject this option if we have less than 60% combat odds
											continue;
										}
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
									}
								}
							}
						}
					}
#ifndef USE_REACHABLE_ENUMERATION
				}
			}
		}
#endif
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_explore()
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pAdjacentPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestExplorePlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iJ;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestExplorePlot = NULL;
	
	bool bNoContact = (GC.getGameINLINE().countCivTeamsAlive() > GET_TEAM(getTeam()).getHasMetCivCount(true));

/************************************************************************************************/
/* Afforess	                  Start		 5/29/11                                                */
/*                                                                                              */
/* AI War Logic                                                                                 */
/************************************************************************************************/
	//When in an offensive war, we are already sending stacks into enemy territory, so exploring
	//in addition to the stacks is counterproductive, and dangerous
	bool bOffenseWar = (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
	if (bOffenseWar && !isHuman() && AI_getUnitAIType() != UNITAI_HUNTER && canAttack())	//	Exempt hunters from this behaviour and also defend-only explorers
	{
		//try to join SoD
		if (AI_group(UNITAI_ATTACK, -1, 1, 6, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK_CITY, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_COLLATERAL, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_COUNTER, -1, 1, 3, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		//try to join attacking stack
		if (AI_group(UNITAI_ATTACK, -1, 1, -1, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK_CITY, -1, 1, -1, false))
		{
			return true;
		}
	}
/*************************************************************************************************/
/**	Afforess									END												**/
/*************************************************************************************************/

	//	If we had previously selected a target make sure we include it in our evaluation this
	//	time around else dithering between different plots can occur
	CvPlot*	pPreviouslySelectedPlot = NULL;
	if ( getGroup()->AI_getMissionAIType() == MISSIONAI_EXPLORE )
	{
		pPreviouslySelectedPlot = getGroup()->AI_getMissionAIPlot();

		if ( pPreviouslySelectedPlot != NULL && atPlot(pPreviouslySelectedPlot) )
		{
			pPreviouslySelectedPlot = NULL;
		}
	}

	std::vector<plotValue>	plotValues;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		PROFILE("AI_explore 1");

		//	Only consider plots that are revealed or adjacent to something we already revealed
		//  ls612: Only consider plots that have no enemy defenders on them
		if (/*AI_plotValid(pLoopPlot) &&*/ !pLoopPlot->isVisibleEnemyDefender(this) && pLoopPlot->area() == area() && (pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam())))
		{
			iValue = 0;

			if (pLoopPlot->isRevealedGoody(getTeam()))
			{
				iValue += 100000;
			}

			if (!(pLoopPlot->isRevealed(getTeam(), false)))
			{
				iValue += 10000;
			}
/*************************************************************************************************/
/**	Xienwolf Tweak							12/13/08											**/
/**																								**/
/**					Reduction in massive Random Spam in Logger files by using Map				**/
/*************************************************************************************************/
/**								---- Start Original Code ----									**
			if (iValue > 0 || GC.getGameINLINE().getSorenRandNum(4, "AI make explore faster ;)") == 0)
/**								----  End Original Code  ----									**/
			if (iValue > 0 || pLoopPlot == pPreviouslySelectedPlot || GC.getGameINLINE().getMapRandNum(4, "AI make explore faster ;)") == 0)
/*************************************************************************************************/
/**	Tweak									END													**/
/*************************************************************************************************/
			{
				// XXX is this too slow?
				for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
				{
					PROFILE("AI_explore 2");

					pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iJ));

					if (pAdjacentPlot != NULL)
					{
						if (!(pAdjacentPlot->isRevealed(getTeam(), false)))
						{
							iValue += 1000;
						}
						else if (bNoContact)
						{
							if (pAdjacentPlot->getRevealedTeam(getTeam(), false) != pAdjacentPlot->getTeam())
							{
								iValue += 100;
							}
						}
					}
				}

				if (iValue > 0)
				{
					if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this)))
					{
/*************************************************************************************************/
/**	Xienwolf Tweak							12/13/08											**/
/**																								**/
/**					Reduction in massive Random Spam in Logger files by using Map				**/
/*************************************************************************************************/
/**								---- Start Original Code ----									**
						iValue += GC.getGameINLINE().getSorenRandNum(250 * abs(xDistance(getX_INLINE(), pLoopPlot->getX_INLINE())) + abs(yDistance(getY_INLINE(), pLoopPlot->getY_INLINE())), "AI explore");
/**								----  End Original Code  ----									**/
						iValue += GC.getGameINLINE().getMapRandNum(250 * abs(xDistance(getX_INLINE(), pLoopPlot->getX_INLINE())) + abs(yDistance(getY_INLINE(), pLoopPlot->getY_INLINE())), "AI explore");
/*************************************************************************************************/
/**	Tweak									END													**/
/*************************************************************************************************/

						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_EXPLORE, getGroup(), 3) == 0)
						{
							//	Add some hysteresis to prevent switching between targets too much
							if ( pPreviouslySelectedPlot == pLoopPlot )
							{
								iValue = (110*iValue)/100;
							}

							if (pLoopPlot->isAdjacentToLand())
							{
								iValue += 10000;
							}

							if (pLoopPlot->isOwned())
							{
								iValue += 5000;
							}
							
							//ls612: Make exploring AI aware of terrain damage
							bool	bHasTerrainDamage = (pLoopPlot->getTerrainTurnDamage(getGroup()) > 0 ||
														 pLoopPlot->getFeatureTurnDamage() > 0);	

							if (bHasTerrainDamage)
							{
								iValue /= 5;
							}

							iValue /= 3 + (std::max(1, itr.stepDistance())/maxMoves());

							if (!atPlot(pLoopPlot) && iValue > 0)
							{
								plotValue thisPlotValue;

								thisPlotValue.plot = pLoopPlot;
								thisPlotValue.value = iValue;

								plotValues.push_back(thisPlotValue);
							}
						}
					}
				}
			}		
		}
	}

	std::sort(plotValues.begin(), plotValues.end(), plotValueSortPredicate);

	for(int iI = plotValues.size()-1; iI >= 0; iI--)
	{
		PROFILE("AI_explore 1.1");

		pLoopPlot = plotValues[iI].plot;
		iValue = plotValues[iI].value;

		if (generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
		{
			PROFILE("AI_explore 1.1.1");
			//	Does this proposed move leave us exposed at the end of this
			//	turn?
			if ( exposedToDanger(getPathEndTurnPlot(), 60) )
			{
				//	Reject this option if we have less than 60% combat odds
				continue;
			}

			pBestPlot = pLoopPlot->isRevealedGoody(getTeam()) ? getPathEndTurnPlot() : pLoopPlot;
			pBestExplorePlot = pLoopPlot;
			break;
		}
	}

	if ((pBestPlot != NULL) && (pBestExplorePlot != NULL))
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY | MOVE_AVOID_ENEMY_UNITS | MOVE_HEAL_AS_NEEDED25, false, false, MISSIONAI_EXPLORE, pBestExplorePlot);
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_exploreRange(int iRange)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pAdjacentPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestExplorePlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;
	int iI;
	bool candidatesRejectedForMoveSafety = false;

	iSearchRange = AI_searchRange(iRange);

/************************************************************************************************/
/* Afforess	                  Start		 5/29/11                                                */
/*                                                                                              */
/* AI War Logic                                                                                 */
/************************************************************************************************/
	//When in an offensive war, we are already sending stacks into enemy territory, so exploring
	//in addition to the stacks is counterproductive, and dangerous
	bool bOffenseWar = (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
	if (bOffenseWar && !isHuman() && AI_getUnitAIType() != UNITAI_HUNTER && canAttack())	//	Exempt hunters from this behaviour and also defend-only explorers
	{
		PROFILE("CvUnitAI::AI_exploreRange.OffensiveWar");

		//try to join SoD
		if (AI_group(UNITAI_ATTACK, -1, 1, 6, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK_CITY, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_COLLATERAL, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_COUNTER, -1, 1, 3, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		//try to join attacking stack
		if (AI_group(UNITAI_ATTACK, -1, 1, -1, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK_CITY, -1, 1, -1, false))
		{
			return true;
		}
	}
/*************************************************************************************************/
/**	Afforess									END												**/
/*************************************************************************************************/

	//	If we had previously selected a target bias towards move in that direction
	CvPlot*	pPreviouslySelectedPlot = NULL;
	if ( getGroup()->AI_getMissionAIType() == MISSIONAI_EXPLORE )
	{
		pPreviouslySelectedPlot = getGroup()->AI_getMissionAIPlot();

		if ( pPreviouslySelectedPlot != NULL && atPlot(pPreviouslySelectedPlot) )
		{
			pPreviouslySelectedPlot = NULL;
		}
	}

	std::vector<plotValue>	plotValues;

	int iImpassableCount = GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType());

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, iSearchRange);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		{
			pLoopPlot = itr.plot();

			//	Have we already considered this plot in a previous invocation?
			int iOpaqueInfo = itr.getOpaqueInfo(ACTIVITY_ID_EXPLORE);
			if ( plotOpaqueInfoMatches(iOpaqueInfo, ACTIVITY_ID_EXPLORE, 1) )
			{
				continue;
			}

			itr.setOpaqueInfo(ACTIVITY_ID_EXPLORE, 1);

			iDX = abs(getX_INLINE()-pLoopPlot->getX_INLINE());
			iDY = abs(getY_INLINE()-pLoopPlot->getY_INLINE());
#else
	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
#endif

			PROFILE("AI_exploreRange 1");

			if (pLoopPlot != NULL && !atPlot(pLoopPlot))
			{
				//	Only consider plots that are revelaed or adjacent to something we already revealed
				if (/*AI_plotValid(pLoopPlot) &&*/ (pLoopPlot->isRevealed(getTeam(), false) || pLoopPlot->isAdjacentRevealed(getTeam())))
				{
					iValue = 0;

					//	Tend to keep heading to the same spot or else dithering, and swapping of
					//	tragets between multiple explorers tends to occur
					if (pLoopPlot == pPreviouslySelectedPlot)
					{
						iValue += 10000;
					}

					if (pLoopPlot->isRevealedGoody(getTeam()))
					{
						iValue += 100000;
					}

					if (!(pLoopPlot->isRevealed(getTeam(), false)))
					{
						iValue += 10000;
					}

					for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
					{
						PROFILE("AI_exploreRange 2");

						pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));

						if (pAdjacentPlot != NULL)
						{
							if (!(pAdjacentPlot->isRevealed(getTeam(), false)))
							{
								iValue += 1000;
							}
						}
					}

					//	plots we can't move into are not worth considering
					if (iValue > 0 && canMoveInto(pLoopPlot))
					{
						if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this)))
						{
							PROFILE("AI_exploreRange 3");

							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_EXPLORE, getGroup(), 3) == 0)
							{
								PROFILE("AI_exploreRange 4");

								if (pLoopPlot->isAdjacentToLand())
								{
									iValue += 10000;
								}

								if (pLoopPlot->isOwned())
								{
									iValue += 5000;
								}
								
								if (!isHuman())
								{
									int iDirectionModifier = 100;

									if (AI_getUnitAIType() == UNITAI_EXPLORE_SEA && iImpassableCount == 0)
									{
										iDirectionModifier += (50 * (abs(iDX) + abs(iDY))) / iSearchRange;
										if (GC.getGame().circumnavigationAvailable())
										{
											if (GC.getMap().isWrapX())
											{
												if ((iDX * ((AI_getBirthmark() % 2 == 0) ? 1 : -1)) > 0)
												{
													iDirectionModifier *= 150 + ((iDX * 100) / iSearchRange);
												}
												else
												{
													iDirectionModifier /= 2;
												}
											}
											if (GC.getMap().isWrapY())
											{
												if ((iDY * (((AI_getBirthmark() >> 1) % 2 == 0) ? 1 : -1)) > 0)
												{
													iDirectionModifier *= 150 + ((iDY * 100) / iSearchRange);
												}
												else
												{
													iDirectionModifier /= 2;
												}
											}
										}
										iValue *= iDirectionModifier;
										iValue /= 100;
									}
								}

/*************************************************************************************************/
/**	Xienwolf Tweak							12/13/08											**/
/**																								**/
/**					Reduction in massive Random Spam in Logger files by using Map				**/
/*************************************************************************************************/
/**								---- Start Original Code ----									**
										iValue += GC.getGameINLINE().getSorenRandNum(10000, "AI Explore");
/**								----  End Original Code  ----									**/
								iValue += GC.getGameINLINE().getMapRandNum(10000, "AI Explore");
/*************************************************************************************************/
/**	Tweak									END													**/
/*************************************************************************************************/
								
								//ls612: Make exploring AI aware of terrain damage
								bool	bHasTerrainDamage = (pLoopPlot->getTerrainTurnDamage(getGroup()) > 0 ||
															 pLoopPlot->getFeatureTurnDamage() > 0);	

								if (bHasTerrainDamage)
								{
									iValue /= 5;
								}

								iValue /= (1 + stepDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()));

								plotValue thisPlotValue;

								thisPlotValue.plot = pLoopPlot;
								thisPlotValue.value = iValue;

								plotValues.push_back(thisPlotValue);
							}
						}
					}
				}
			}
		}
	}

	iBestValue = 0;
	pBestPlot = NULL;
	pBestExplorePlot = NULL;

	//	Sort the plots found on their values
	while(plotValues.size() > 0)
	{
		std::sort(plotValues.begin(), plotValues.end(), plotValueSortPredicate);

		iValue = plotValues[plotValues.size()-1].value;
		pLoopPlot = plotValues[plotValues.size()-1].plot;

		if ( iValue == 0 )
		{
			break;
		}

		//	Avoid the cost of path generation if this cannot possibly be the best result
#ifdef USE_REACHABLE_ENUMERATION
		CvReachablePlotSet::const_iterator itr = plotSet.find(pLoopPlot);
		if (itr != plotSet.end() && generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns, iRange))
#else
		if (generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
#endif
		{
			//	Don't limit by iPathTurns since the range param passedin is really advisory
			//	only and intended to limit the size of the search space

			//	Does this proposed move leave us exposed at the end of this
			//	turn?  For general exploring moves we accept danger with 60%
			//	combat odds in our favour
			if ( exposedToDanger(getPathEndTurnPlot(),60) )
			{
				//	For now just reject this.  Might want to do a combat odds check ideally
				candidatesRejectedForMoveSafety = true;
			}
			else
			{
				iBestValue = iValue;
				if (getDomainType() == DOMAIN_LAND)
				{
					pBestPlot = getPathEndTurnPlot();
				}
				else
				{
					pBestPlot = pLoopPlot;
				}
				pBestExplorePlot = pLoopPlot;
				break;
			}
		}
		else
		{
#ifdef USE_REACHABLE_ENUMERATION
			//	It's actually out of range for this search so we have not really meaningfully checked it
			itr.setOpaqueInfo(ACTIVITY_ID_EXPLORE, 0);
#endif
			//	Redistribute the score of the top plot (which we could not reach) to other candidates
			//	According to their distance from it.  This creates a bias to explore towards the high
			//	value plot that we cannot yet find a path to
			for(int iI = 0; iI < (int)plotValues.size()-1; iI++)
			{
				//	Can knock out candidates that are adjacent to the one we just tried to path to since we won't be able to reach them
				//	either (unless both are unrevealed potentially)
				if ( stepDistance(pLoopPlot->getX_INLINE(),pLoopPlot->getY_INLINE(),plotValues[iI].plot->getX_INLINE(),plotValues[iI].plot->getY_INLINE()) == 1 &&
					 (pLoopPlot->isRevealed(getTeam(),false) || plotValues[iI].plot->isRevealed(getTeam(),false)) )
				{
					plotValues[iI].value = 0;
				}
				else if ( plotValues[iI].value > 0 )
				{
					plotValues[iI].value += iValue/(5*std::max(1,plotDistance(pLoopPlot->getX_INLINE(),pLoopPlot->getY_INLINE(),plotValues[iI].plot->getX_INLINE(),plotValues[iI].plot->getY_INLINE())));
				}
			}
		}

		plotValues.resize(plotValues.size()-1);
	}

	if ((pBestPlot != NULL) && (pBestExplorePlot != NULL))
	{
		OutputDebugString(CvString::format("%S (%d) chooses to explore move to (%d,%d)\n",getDescription().c_str(),m_iID,pBestPlot->getX_INLINE(),pBestPlot->getY_INLINE()).c_str());
		PROFILE("AI_exploreRange 5");

		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY | MOVE_HEAL_AS_NEEDED25, false, false, MISSIONAI_EXPLORE, pBestExplorePlot);
	}
	else if ( candidatesRejectedForMoveSafety )
	{
		OutputDebugString(CvString::format("%S (%d) finds danger blocking explore move an seeks safety\n",getDescription().c_str(),m_iID).c_str());
		//	Just stay safe for a while
		return AI_safety();
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_refreshExploreRange(int iRange, bool bIncludeVisibilityRefresh)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pAdjacentPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestExplorePlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	//int iDX, iDY;
	int iI;
	bool candidatesRejectedForMoveSafety = false;

	iSearchRange = AI_searchRange(iRange);

	//	If we had previously selected a target bias towards move in that direction
	CvPlot*	pPreviouslySelectedPlot = NULL;
	if ( getGroup()->AI_getMissionAIType() == MISSIONAI_EXPLORE )
	{
		pPreviouslySelectedPlot = getGroup()->AI_getMissionAIPlot();

		if ( pPreviouslySelectedPlot != NULL && atPlot(pPreviouslySelectedPlot) )
		{
			pPreviouslySelectedPlot = NULL;
		}
	}

/************************************************************************************************/
/* Afforess	                  Start		 5/29/11                                                */
/*                                                                                              */
/* AI War Logic                                                                                 */
/************************************************************************************************/
	//When in an offensive war, we are already sending stacks into enemy territory, so exploring
	//in addition to the stacks is counterproductive, and dangerous
	bool bOffenseWar = (area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE);
	if (bOffenseWar && !isHuman() && AI_getUnitAIType() != UNITAI_HUNTER && canAttack())	//	Exempt hunters from this behaviour and also defend-only explorers
	{
		//try to join SoD
		if (AI_group(UNITAI_ATTACK, -1, 1, 6, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK_CITY, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_COLLATERAL, -1, 1, 4, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		if (AI_group(UNITAI_COUNTER, -1, 1, 3, false, false, true, MAX_INT, true, false, false))
		{
			return true;
		}
		//try to join attacking stack
		if (AI_group(UNITAI_ATTACK, -1, 1, -1, false))
		{
			return true;
		}
		if (AI_group(UNITAI_ATTACK_CITY, -1, 1, -1, false))
		{
			return true;
		}
	}
/*************************************************************************************************/
/**	Afforess									END												**/
/*************************************************************************************************/

	iBestValue = 0;
	pBestPlot = NULL;
	pBestExplorePlot = NULL;

	int iImpassableCount = GET_PLAYER(getOwnerINLINE()).AI_unitImpassableCount(getUnitType());

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), MOVE_NO_ENEMY_TERRITORY, iSearchRange);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
#endif
			PROFILE("AI_exploreRange 1");
	
			if (pLoopPlot != NULL && !atPlot(pLoopPlot))
			{
				//if (AI_plotValid(pLoopPlot))
				{
					int iAdjacentEnemies = 0;
					bool bValidAdjacentEnemyValue = false;

					iValue = 0;

					if (pLoopPlot->isRevealedGoody(getTeam()))
					{
						iValue += 100000;
					}

					if (!(pLoopPlot->isRevealed(getTeam(), false)))
					{
						iValue += 10000;
					}

					if ( bIncludeVisibilityRefresh && !pLoopPlot->isVisible(getTeam(),false) )
					{
						iValue += (GC.getGameINLINE().getGameTurn() - pLoopPlot->getLastVisibleTurn(getTeam()));
					}

					for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
					{
						PROFILE("AI_exploreRange 2");

						pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));

						if (pAdjacentPlot != NULL)
						{
							if (!(pAdjacentPlot->isRevealed(getTeam(), false)))
							{
								iValue += 1000;
							}

							//	If there is an enemy unit there add an extra value to the adjacent plot
							//	we are currently considering so as to consider moving there to tempt the enemy
							//	into an attack more favourable to us than us attacking them (which will already
							//	have been considered).  We will only actually consider this value if we can get
							//	there this turn however, since units move!
							if ( AI_plotValid(pAdjacentPlot) &&
								 stepDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getX_INLINE(), getY_INLINE()) <= AI_searchRange(1) )
							{
								CLLNode<IDInfo>* pUnitNode = pAdjacentPlot->headUnitNode();
								while (pUnitNode != NULL)
								{
									CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
									pUnitNode = pAdjacentPlot->nextUnitNode(pUnitNode);

									//	Animals won't attack into owned territory so don't count them
									if (isEnemy(pLoopUnit->getTeam()) &&
										(pLoopPlot->getOwnerINLINE() == NO_PLAYER || !pLoopUnit->isAnimal()))
									{
										iAdjacentEnemies++;

										//	Don't count extra value for might-be-attacked in owned territory.  This stops units
										//	getting stuck oscillating back and forth between two defensive tiles next to foreign
										//	(esp barbarian) cities when they should be hunting/exploring
										if ( pAdjacentPlot->getOwnerINLINE() == NO_PLAYER || pAdjacentPlot->getOwnerINLINE() == getOwnerINLINE() )
										{
											bValidAdjacentEnemyValue = true;
										}
									}
								}
							}
						}
					}

					//bValidAdjacentEnemyValue &= (iAdjacentEnemies == 1);
					if (iValue > 0 || bValidAdjacentEnemyValue)
					{
						if (!pLoopPlot->isVisible(getTeam(),false) || !(pLoopPlot->isVisibleEnemyUnit(this)))
						{
							PROFILE("AI_exploreRange 3");

							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_EXPLORE, getGroup(), 3) == 0)
							{
								PROFILE("AI_exploreRange 4");

								//	Avoid the cost of path generation if this cannot possibly be the best result
								if ( (iValue > iBestValue - 50 - (bValidAdjacentEnemyValue ? 50 : 0)) && generatePath(pLoopPlot, MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns, iRange))
								{
									if (iPathTurns <= iRange)
									{
										iValue += GC.getGameINLINE().getMapRandNum(50, "AI Explore");

										if ( bValidAdjacentEnemyValue && iPathTurns <= 1 )
										{
											iValue += 50 + pLoopPlot->defenseModifier(getTeam(), false);	//	Chance to prompt a favorable attack
										}

										//	Try to pick something that moves towards our eventual goal (if any)
										if ( pPreviouslySelectedPlot != NULL )
										{
											iValue += 50*(stepDistance(pPreviouslySelectedPlot->getX_INLINE(), pPreviouslySelectedPlot->getY_INLINE(), getX_INLINE(), getY_INLINE()) -
														  stepDistance(pPreviouslySelectedPlot->getX_INLINE(), pPreviouslySelectedPlot->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()));
										}

										//ls612: Make exploring AI aware of terrain damage
										bool	bHasTerrainDamage = (pLoopPlot->getTerrainTurnDamage(getGroup()) > 0 ||
																	 pLoopPlot->getFeatureTurnDamage() > 0);	

										if (bHasTerrainDamage)
										{
											iValue /= 5;
										}

										if (iValue > iBestValue)
										{
											//	Does this proposed move leave us exposed at the end of this
											//	turn?  For general exploring moves we accept danger with 60%
											//	combat odds in our favour
											if ( exposedToDanger(getPathEndTurnPlot(),60) )
											{
												//	For now just reject this.  Might want to do a combat odds check ideally
												candidatesRejectedForMoveSafety = true;
												continue;
											}
											iBestValue = iValue;
											if (getDomainType() == DOMAIN_LAND)
											{
												pBestPlot = getPathEndTurnPlot();
											}
											else
											{
												pBestPlot = pLoopPlot;
											}
											pBestExplorePlot = pLoopPlot;
										}
									}
								}
							}
						}
					}
				}
			}
#ifndef USE_REACHABLE_ENUMERATION
		}
#endif
	}

	if ((pBestPlot != NULL) && (pBestExplorePlot != NULL))
	{
		PROFILE("AI_exploreRange 5");

		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY | MOVE_HEAL_AS_NEEDED25, false, false, MISSIONAI_EXPLORE, pPreviouslySelectedPlot != NULL ? pPreviouslySelectedPlot : pBestExplorePlot);
	}
	else if ( candidatesRejectedForMoveSafety )
	{
		//	Just stay safe for a while
		return AI_safety();
	}

	return false;
}

//	Determine if there is a threatening unit at the spcified plot.
//	Return a pointer to the unit if so (NULL with a detected threat means multiple units)
bool	CvUnitAI::getThreateningUnit(CvPlot* pPlot, CvUnit*& pThreateningUnit, CvPlot* pAttackPlot, int& iIndex, bool bReturnWorstOfMultiple) const
{
	int iOdds = 0;
	int iWorstOdds = 0;
	int iI = 0;

	pThreateningUnit = NULL;

	if ( bReturnWorstOfMultiple && iIndex != 0 )
	{
		return false;
	}

	CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
	while (pUnitNode != NULL)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		//	Don't count animals if the target plot is owned since they cannot attack there
		if (isEnemy(pLoopUnit->getTeam()) && pLoopUnit->canAttack() && (!pLoopUnit->isAnimal() || pAttackPlot->getOwnerINLINE() == NO_PLAYER))
		{
			if ( bReturnWorstOfMultiple )
			{
				if ( pPlot == pAttackPlot )
				{
					iOdds = 100 - ((CvUnitAI*)this)->AI_attackOddsAtPlot(pPlot, pLoopUnit);
				}
				else
				{
					iOdds = pLoopUnit->AI_attackOddsAtPlot(pPlot, (CvUnitAI*)this);
				}

				if ( iOdds > iWorstOdds )
				{
					iWorstOdds = iOdds;
					pThreateningUnit = pLoopUnit;

					iIndex++;
				}
			}
			else
			{
				if ( iI++ == iIndex )
				{
					iIndex++;

					pThreateningUnit = pLoopUnit;
					return true;
				}
			}
		}
	}

	return (pThreateningUnit != NULL);
}

bool CvUnitAI::exposedToDanger(CvPlot* pPlot, int acceptableOdds, bool bConsiderOnlyWorstThreat) const
{
	if ( GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pPlot, 1, false) )
	{
		//	What would the odds be?
		//	We use a cheapskate heuristic if there are multiple threatening
		//	units and just assume that any more than 1 is a no-no
		CvUnit*	threateningUnit = NULL;
		int iOurOdds = 100;
		int iIndex;

		int iOurValue = 0;
		int iEnemyTotalValueExpectedLoss = 0;
		CvUnit* pOurAttacker = NULL;

		//	If we're not currently at the designated plot check it first on the assumption we'll want to
		//	attack into it if we are capable of so doing
		if ( pPlot != plot() && pPlot->isVisibleEnemyUnit(this) )
		{
			iIndex = 0;

			//	Evaluate based on our best attacker
			int dummy;
			pOurAttacker = getGroup()->AI_getBestGroupAttacker(pPlot, true, dummy);

			if ( pOurAttacker == NULL )
			{
				//	We cannot attack here
				return true;
			}
			else
			{
				iOurValue += pOurAttacker->AI_genericUnitValueTimes100(UNITVALUE_FLAGS_DEFENSIVE | UNITVALUE_FLAGS_OFFENSIVE);

				while ( getThreateningUnit(pPlot, threateningUnit, pPlot, iIndex, bConsiderOnlyWorstThreat) )
				{
					int iOdds = ((CvUnitAI*)pOurAttacker)->AI_attackOddsAtPlot(pPlot, threateningUnit);

					//	AI_attackOddsAtPlot returns a value capped artifically at 99, but for the ensuing calculation
					//	that causes nasty rounding errors so we just treat 99 as if it were certainty
					if ( iOdds == 99 )
					{
						iOdds = 100;
					}
					//	Survival probability is probability of surviving up to this (iOurOdds
					//	up to this point) * odds of surving this encounter, which we normalize
					//	from the base (100-iOdds) by a factor of iOurOdds to reflect likely damage taken
					iOurOdds = (iOurOdds*iOdds*iOurOdds)/10000;

					if ( iOurOdds > 50 )
					{
						 int iEnemyValue = threateningUnit->AI_genericUnitValueTimes100(UNITVALUE_FLAGS_DEFENSIVE | UNITVALUE_FLAGS_OFFENSIVE);
						 
						 //	Only count one kill - this routine is mostly geared towards single unit stacks so we'll
						 //	only normally be actually attacking once
						 if ( iEnemyValue > iEnemyTotalValueExpectedLoss )
						 {
							 iEnemyTotalValueExpectedLoss = iEnemyValue;
						 }
					}

					if ( bConsiderOnlyWorstThreat )
					{
						break;
					}
				}
			}
		}

		//	Koshling - this loop used to go from -1 (i.e. - inlcude the plot itself, but
		//	the clause above deals with that so it seems wrong, and I have changed it)
		CvUnit* pOurDefender = ((CvSelectionGroupAI*)getGroup())->AI_findBestDefender(pPlot, true);

		if ( pOurAttacker != pOurDefender )
		{
			iOurValue += pOurDefender->AI_genericUnitValueTimes100(UNITVALUE_FLAGS_DEFENSIVE | UNITVALUE_FLAGS_OFFENSIVE);
		}

		for (int iI = 0; iI < NUM_DIRECTION_TYPES && iOurOdds >= acceptableOdds; iI++)
		{
			CvPlot* pAdjacentPlot;
			
			if ( iI == -1 )
			{
				pAdjacentPlot = pPlot;
			}
			else
			{
				pAdjacentPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));
			}

			if (pAdjacentPlot != NULL)
			{
				if (AI_plotValid(pAdjacentPlot))
				{
					CvUnit* pUnit;
					
					iIndex = 0;

					while ( getThreateningUnit(pAdjacentPlot, pUnit, pPlot, iIndex, bConsiderOnlyWorstThreat) )
					{
						FAssert(pUnit != NULL);

						if ( !isInvisible( pUnit->getTeam(), false ) )
						{
							int iOdds = pUnit->AI_attackOddsAtPlot(pPlot,(CvUnitAI*)pOurDefender);

							//	AI_attackOddsAtPlot returns a value capped artifically below at 1, but for the ensuing calculation
							//	that causes nasty rounding errors so we just treat 1 as if it were certainty of failure
							if ( iOdds == 1 )
							{
								iOdds = 0;
							}

							if ( bConsiderOnlyWorstThreat )
							{
								if ( threateningUnit != NULL )
								{
									if ( iOdds > 100 - iOurOdds )
									{
										threateningUnit = pUnit;
										iOurOdds = 100 - iOdds;
									}
								}
								else
								{
									iOurOdds = 100 - iOdds;
								}

								break;
							}
							else
							{
								//	Survival probability is probability of surviving up to this (iOurOdds
								//	up to this point) * odds of surving this encounter, which we normalize
								//	from the base (100-iOdds) by a factor of iOurOdds to reflect likely damage taken
								iOurOdds = (iOurOdds*(100 - iOdds)*iOurOdds)/10000;

								//	Since all enemies can attack us, count them all
								if ( iOurOdds > 50 )
								{
									iEnemyTotalValueExpectedLoss += pUnit->AI_genericUnitValueTimes100(UNITVALUE_FLAGS_DEFENSIVE | UNITVALUE_FLAGS_OFFENSIVE);
								}
							}
						}
					}
				}
			}
		}

		if ( iOurOdds < acceptableOdds && iEnemyTotalValueExpectedLoss >= iOurValue )
		{
			//	If we would claim this is too dangerous adjust for relative losses so that
			//	things that leave us likely to die only if we take a lot of enemeies with us
			//	are considered ok - note that we only apply this adjustnment to single unit
			//	stacks, since use of this routine with  multi-unit stacks is limitted to situations
			//	where escorts (of defenseless, but relatively important) units is involved
			if ( getGroup()->getNumUnits() == 1 )
			{
				iOurOdds += ((100-iOurOdds)*(iEnemyTotalValueExpectedLoss-iOurValue))/(2*std::max(1, iOurValue));
			}
		}

		return (iOurOdds < acceptableOdds);
	}
	else
	{
		return false;
	}
}

typedef struct
{
	int		iValue;
	CvCity*	pCity;
} targetInfo;
#define	MAX_CLOSE_TARGET_DISTANCE	5

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/29/10                                jdog5000      */
/*                                                                                              */
/* War tactics AI, Efficiency                                                                   */
/************************************************************************************************/
// Returns target city
CvCity* CvUnitAI::AI_pickTargetCity(int iFlags, int iMaxPathTurns, bool bHuntBarbs )
{
	PROFILE_FUNC();

	CvCity* pTargetCity = NULL;
	CvCity* pLoopCity;
	CvCity* pBestCity;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;
	static std::map<CvPlot*,bool>* cachedTargets = NULL;

	iBestValue = 0;
	pBestCity = NULL;

	//pTargetCity = area()->getTargetCity(getOwnerINLINE());

	// Don't always go after area target ... don't know how far away it is
	/*
	if (pTargetCity != NULL)
	{
		if (AI_potentialEnemy(pTargetCity->getTeam(), pTargetCity->plot()))
		{
			if (!atPlot(pTargetCity->plot()) && generatePath(pTargetCity->plot(), iFlags, true))
			{
				pBestCity = pTargetCity;
			}
		}
	}
	*/
	if ( cachedTargets == NULL )
	{
		cachedTargets = new std::map<CvPlot*,bool>();
	}

	if ( eCachedTargetCityPlayer != getOwnerINLINE() )
	{
		eCachedTargetCityPlayer = getOwnerINLINE();
		cachedTargets->clear();
	}

	for(std::map<CvPlot*,bool>::const_iterator itr = cachedTargets->begin(); itr != cachedTargets->end(); ++itr)
	{
		CvCity* possibleTargetCity = itr->first->getPlotCity();

		if ( possibleTargetCity != NULL &&
			 itr->first->area() == area() &&
			 stepDistance(getX_INLINE(), getY_INLINE(), itr->first->getX_INLINE(), itr->first->getY_INLINE()) < AI_searchRange(iMaxPathTurns) &&
			 generatePath(itr->first, iFlags, true, NULL, MAX_CLOSE_TARGET_DISTANCE) )
		{
			pBestCity = possibleTargetCity;
			break;
		}
	}

	CvReachablePlotSet plotSet(getGroup(), iFlags);

	if ( iMaxPathTurns != MAX_INT )
	{
		plotSet.Populate(AI_searchRange(iMaxPathTurns));
	}

	std::multimap<int,targetInfo> possibleTargets;

	if (pBestCity == NULL)
	{
		for (iI = 0; iI < (bHuntBarbs ? MAX_PLAYERS : MAX_CIV_PLAYERS); iI++)
		{
			if (GET_PLAYER((PlayerTypes)iI).isAlive() && ::isPotentialEnemy(getTeam(), GET_PLAYER((PlayerTypes)iI).getTeam()))
			{
				for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
				{
					// BBAI efficiency: check area for land units before generating path
					if (((iMaxPathTurns == MAX_INT && stepDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()) < AI_searchRange(iMaxPathTurns)) ||
						(iMaxPathTurns != MAX_INT && plotSet.find(pLoopCity->plot()) != plotSet.end())) &&
						pLoopCity->plot()->isRevealed(getTeam(),false) &&
						(getDomainType() != DOMAIN_LAND || pLoopCity->area() == area()))
					{
						if(AI_potentialEnemy(GET_PLAYER((PlayerTypes)iI).getTeam(), pLoopCity->plot()))
						{
							if (!atPlot(pLoopCity->plot()))
							{
								iValue = 0;
								if (AI_getUnitAIType() == UNITAI_ATTACK_CITY) //lemming?
								{
									iValue = GET_PLAYER(getOwnerINLINE()).AI_targetCityValue(pLoopCity, false, false);
								}
								else
								{
									iValue = GET_PLAYER(getOwnerINLINE()).AI_targetCityValue(pLoopCity, true, true);
								}

								if( pLoopCity == pTargetCity )
								{
									iValue *= 2;
								}
								
								if ((area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE))
								{
									iValue *= 50 + pLoopCity->calculateCulturePercent(getOwnerINLINE());
									iValue /= 50;
								}

								iValue *= 1000;

								// If city is minor civ, less interesting
								if( GET_PLAYER(pLoopCity->getOwnerINLINE()).isMinorCiv() || GET_PLAYER(pLoopCity->getOwnerINLINE()).isBarbarian() )
								{
									iValue /= 2;
								}

								if ( iValue > 0 )
								{
									targetInfo info;

									info.iValue = iValue;
									info.pCity = pLoopCity;

									int iDistanceEstimate = (stepDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()) + 2)/2;
									int	iOrderingValue = -iValue/(iDistanceEstimate*iDistanceEstimate);

									possibleTargets.insert(std::make_pair(iOrderingValue, info));
								}
							}
						}
					}
				}
			}
		}
	}

	bool bVerifiedPathing = false;

	if (pBestCity == NULL)
	{
		//	Following loop verifies
		bVerifiedPathing = true;

		for(std::multimap<int,targetInfo>::const_iterator itr = possibleTargets.begin(); itr != possibleTargets.end(); ++itr)
		{
			CvCity* pLoopCity = itr->second.pCity;
			int		iPathTurnsExtra = std::min(12, getGroup()->getBombardTurns(pLoopCity)/4);
			int		iMaxPath;

			if ( iBestValue > 0 )
			{
				float	fLongestPossibleWinningPath = sqrt(((float)itr->second.iValue)/((float)iBestValue) - 4);

				iMaxPath = std::min((int)fLongestPossibleWinningPath - iPathTurnsExtra, iMaxPathTurns);
			}
			else
			{
				iMaxPath = iMaxPathTurns;
			}

			if ( iMaxPath > 0 )
			{
				PROFILE("AI_pickTargetCity.PrePathing");
				if (generatePath(pLoopCity->plot(), iFlags, true, &iPathTurns, iMaxPath) ||
					(stepDistance(pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), getX_INLINE(), getY_INLINE()) == 1 &&
					 getGroup()->canBombard(plot(),true)))
				{
					PROFILE("AI_pickTargetCity.PostPathing");

					// If city is visible and our force already in position is dominantly powerful or we have a huge force
					// already on the way, pick a different target
					if( iPathTurns > 2 && pLoopCity->isVisible(getTeam(), false) )
					{
						/*
						int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pLoopCity->plot(),2,false,false,true);	
						int iEnemyDefense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pLoopCity->plot(),1,true,false);

						if( 100*iOurOffense >= GC.getBBAI_SKIP_BOMBARD_BASE_STACK_RATIO()*iEnemyDefense )
						{
							continue;
						}
						*/

						if( GET_PLAYER(getOwnerINLINE()).AI_cityTargetUnitsByPath(pLoopCity, getGroup(), iPathTurns) > std::max( 6, 3 * pLoopCity->plot()->getNumVisibleEnemyDefenders(this) ) )
						{
							continue;
						}
					}

					//	For barbarians, if the city is distant, build a larger stack first than we
					//	would if it were close by
					if ( isBarbarian() )
					{
						int	iMinStack = 3 + iPathTurns/5;

						if ( getGroup()->getNumUnits() < iMinStack )
						{
							continue;
						}
					}

					iValue = itr->second.iValue/(4 + iPathTurns*iPathTurns);

					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						pBestCity = pLoopCity;
					}
				}
			}
		}
	}

	if ( pBestCity != NULL )
	{
		if ( !bVerifiedPathing && !generatePath(pBestCity->plot(), iFlags, true) )
		{
			pBestCity = NULL;
		}
		else
		{
			logBBAI("Unit %d at (%d,%d) picks target city at (%d,%d)",
					getID(),
					getX_INLINE(),
					getY_INLINE(),
					pBestCity->getX_INLINE(),
					pBestCity->getY_INLINE());

			(*cachedTargets)[pBestCity->plot()] = true;
		}
	}

	return pBestCity;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_goToTargetCity(int iFlags, int iMaxPathTurns, CvCity* pTargetCity )
{
	PROFILE_FUNC();

	CvPlot* pAdjacentPlot;
	CvPlot* pBestPlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iI;

	if( pTargetCity == NULL )
	{
		pTargetCity = AI_pickTargetCity(iFlags, iMaxPathTurns);
	}

	if (pTargetCity != NULL)
	{
		PROFILE("CvUnitAI::AI_targetCity plot attack");
		iBestValue = 0;
		pBestPlot = NULL;

		if (0 == (iFlags & MOVE_THROUGH_ENEMY))
		{
			bool bAttemptWithoutMovingThroughEnemy = true;
			bool bNeedToPathThroughEnemy = false;

			do
			{
				for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
				{
					pAdjacentPlot = plotDirection(pTargetCity->getX_INLINE(), pTargetCity->getY_INLINE(), ((DirectionTypes)iI));

					if (pAdjacentPlot != NULL)
					{
						if (AI_plotValid(pAdjacentPlot))
						{
							if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
							{
								if (generatePath(pAdjacentPlot, iFlags, true, &iPathTurns, iMaxPathTurns))
								{
									iValue = std::max(0, (pAdjacentPlot->defenseModifier(getTeam(), false) + 100));

									if (!(pAdjacentPlot->isRiverCrossing(directionXY(pAdjacentPlot, pTargetCity->plot()))))
									{
										iValue += (12 * -(GC.getRIVER_ATTACK_MODIFIER()));
									}

									if (!isEnemy(pAdjacentPlot->getTeam(), pAdjacentPlot))
									{
										iValue += 100;                                
									}

									if( atPlot(pAdjacentPlot) )
									{
										iValue += 50;
									}

									iValue = std::max(1, iValue);

									iValue *= 1000;

									iValue /= (iPathTurns + 1);

									if (iValue > iBestValue)
									{
										CvPlot* endTurnPlot = getPathEndTurnPlot();
										bool bAcceptable;

										if ( pAdjacentPlot == endTurnPlot )
										{
											bAcceptable = true;
										}
										else if ( getGroup()->getNumUnits() < 3 )
										{
											bAcceptable = !exposedToDanger(endTurnPlot, 60);
										}
										else
										{
											int iTotalEnemyStrength = endTurnPlot->getVisibleEnemyStrength(getOwnerINLINE(), 1);
											int	iOurStrength = plot()->plotStrength((UnitValueFlags)(UNITVALUE_FLAGS_OFFENSIVE | UNITVALUE_FLAGS_DEFENSIVE),NULL,-1,-1,getOwnerINLINE());

											bAcceptable = (iOurStrength > 2*iTotalEnemyStrength);
										}

										if ( bAcceptable )
										{
											iBestValue = iValue;
											pBestPlot = endTurnPlot;
										}
									}
								}
							}
						}
					}
				}

				//	If we failed to find any path without moving through enemy units retry
				//	accepting we might have to
				bAttemptWithoutMovingThroughEnemy = !bAttemptWithoutMovingThroughEnemy;
				if ( pBestPlot == NULL )
				{
					iFlags |= MOVE_THROUGH_ENEMY;
					bNeedToPathThroughEnemy = true;
				}
			} while( !bAttemptWithoutMovingThroughEnemy && pBestPlot == NULL );

			if ( bNeedToPathThroughEnemy && pBestPlot != NULL )
			{
				//	TODO - add some sort of sanity check that we can reasonably expect
				//	to get through them!
				CvPath& kPath = getGroup()->getPath();

				for(CvPath::const_iterator itr = kPath.begin(); itr != kPath.end() && itr.plot() != pTargetCity->plot(); ++itr)
				{
					CvPlot* pPathPlot = itr.plot();

					if ( pPathPlot->isVisibleEnemyUnit(getOwnerINLINE()) )
					{
						bool bWin;
						int iExpectedGainOdds = getGroup()->AI_attackOdds(pPathPlot, true, false, &bWin);

						if ( iExpectedGainOdds < 50 )
						{
							if ( !bWin )
							{
								//	Blockade is too strong to beat
								pBestPlot = NULL;
							}
							else
							{
								int iStackRatio = getGroup()->AI_compareStacks(pPathPlot, true);

								//	If we won, but with low expected gain odds it might still be worthwhile
								//	to break the bottleneck - renormalize by the ratio of starting stack
								//	strengths.  This will allow a very numerous stack to plough through
								//	a small, but strong garrison even though doing so is locally a loss
								iExpectedGainOdds *= iStackRatio;
								iExpectedGainOdds /= 100;

								if ( iExpectedGainOdds < 50 )
								{
									//	Really not worth it
									pBestPlot = NULL;
								}
							}
						}
					}
				}
			}
		}
		else
		{
			pBestPlot =  pTargetCity->plot();
		}

		if (pBestPlot != NULL)
		{
			FAssert(!(pTargetCity->at(pBestPlot)) || 0 != (iFlags & MOVE_THROUGH_ENEMY)); // no suicide missions...
			if (!atPlot(pBestPlot))
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), iFlags);
			}
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_goToTargetBarbCity(int iMaxPathTurns)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvCity* pBestCity;
	CvPlot* pAdjacentPlot;
	CvPlot* pBestPlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;

	if (isBarbarian())
	{
		return false;
	}

	iBestValue = 0;
	pBestCity = NULL;

	for (pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(BARBARIAN_PLAYER).nextCity(&iLoop))
	{
		if (AI_plotValid(pLoopCity->plot()))
		{
			// BBAI efficiency: check area for land units before generating path
			if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
			{
				continue;
			}
			if (pLoopCity->isRevealed(getTeam(), false))
			{
				if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
				{
					if (iPathTurns < iMaxPathTurns)
					{
						iValue = GET_PLAYER(getOwnerINLINE()).AI_targetCityValue(pLoopCity, false);

						iValue *= 1000;

						iValue /= (iPathTurns + 1);

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestCity = pLoopCity;
						}
					}
				}
			}
		}
	}

	if (pBestCity != NULL)
	{
		iBestValue = 0;
		pBestPlot = NULL;

		for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
		{
			pAdjacentPlot = plotDirection(pBestCity->getX_INLINE(), pBestCity->getY_INLINE(), ((DirectionTypes)iI));

			if (pAdjacentPlot != NULL)
			{
				if (AI_plotValid(pAdjacentPlot))
				{
					if (!(pAdjacentPlot->isVisibleEnemyUnit(this)))
					{
						if (generatePath(pAdjacentPlot, 0, true, &iPathTurns, iMaxPathTurns))
						{
							iValue = std::max(0, (pAdjacentPlot->defenseModifier(getTeam(), false) + 100));

							if (!(pAdjacentPlot->isRiverCrossing(directionXY(pAdjacentPlot, pBestCity->plot()))))
							{
								iValue += (10 * -(GC.getRIVER_ATTACK_MODIFIER()));
							}

							iValue = std::max(1, iValue);

							iValue *= 1000;

							iValue /= (iPathTurns + 1);

							if (iValue > iBestValue)
							{
								CvPlot* endTurnPlot = getPathEndTurnPlot();

								if ( !exposedToDanger(endTurnPlot, 60) )
								{
									iBestValue = iValue;
									pBestPlot = endTurnPlot;
								}
							}
						}
					}
				}
			}
		}

		if (pBestPlot != NULL)
		{
			FAssert(!(pBestCity->at(pBestPlot))); // no suicide missions...
			if (atPlot(pBestPlot))
			{
				getGroup()->pushMission(MISSION_SKIP);
				return true;
			}
			else
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
			}
		}
	}

	return false;
}

bool CvUnitAI::AI_pillageAroundCity(CvCity* pTargetCity, int iBonusValueThreshold, int iMaxPathTurns )
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestPillagePlot;
	int iPathTurns;
	int iValue;
	int iBestValue;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestPillagePlot = NULL;

	for( int iI = 0; iI < NUM_CITY_PLOTS; iI++ )
	{
		pLoopPlot = pTargetCity->getCityIndexPlot(iI);

		if (pLoopPlot != NULL)
		{
			if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
			{
				if (potentialWarAction(pLoopPlot) && (pLoopPlot->getTeam() == pTargetCity->getTeam()))
				{
                    if (getGroup()->canPillage(pLoopPlot))
                    {
                        if (!(pLoopPlot->isVisibleEnemyUnit(this)))
                        {
                            if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
                            {
                                if (generatePath(pLoopPlot, 0, true, &iPathTurns, iMaxPathTurns))
                                {
                                    iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);

									iValue *= 1000 + 30*(pLoopPlot->defenseModifier(getTeam(),false));

                                    iValue /= (iPathTurns + 1);

									// if not at war with this plot owner, then devalue plot if we already inside this owner's borders
									// (because declaring war will pop us some unknown distance away)
									if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
									{
										iValue /= 10;
									}

                                    if (iValue > iBestValue)
                                    {
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( !exposedToDanger(endTurnPlot, 60) )
										{
											iBestValue = iValue;
											pBestPlot = endTurnPlot;
											pBestPillagePlot = pLoopPlot;
										}
                                    }
                                }
                            }
                        }
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
	{
		if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
		{
			//getGroup()->groupDeclareWar(pBestPillagePlot, true);
			// rather than declare war, just find something else to do, since we may already be deep in enemy territory
			return false;
		}
		
		if (atPlot(pBestPillagePlot))
		{
			if (isEnemy(pBestPillagePlot->getTeam()))
			{
				getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
				return true;
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
		}
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_bombardCity()
{
	PROFILE_FUNC();

	//	Replaced REV implementation with K-mod simplified one
	//	[FUTURE] - may want to use contract brokerage to get bombers and ships to bombard first
	if (getGroup()->canBombard(plot())) 
	{
		CvCity* pBombardCity = bombardTarget(plot());

		if ( pBombardCity != NULL )
		{
			int iAttackOdds = getGroup()->AI_attackOdds(pBombardCity->plot(), true); 
			int iBase = GC.getBBAI_SKIP_BOMBARD_BASE_STACK_RATIO(); 
			int iMin = GC.getBBAI_SKIP_BOMBARD_MIN_STACK_RATIO(); 
			int iBombardTurns = getGroup()->getBombardTurns(pBombardCity); 
			int iThreshold = (iBase * (100 - iAttackOdds) + (1 + iBombardTurns/2) * iMin * iAttackOdds) / (100 + (iBombardTurns/2) * iAttackOdds); 
			int iComparison = getGroup()->AI_compareStacks(pBombardCity->plot(), true, true, true);

			if (iComparison > iThreshold && pBombardCity->isDirectAttackable()) 
			{ 
				if( gUnitLogLevel > 2 )
				{
					logBBAI("      Stack skipping bombard of %S with compare %d, starting odds %d, bombard turns %d, threshold %d", pBombardCity->getName().GetCString(), iComparison, iAttackOdds, iBombardTurns, iThreshold); 
				}
			} 
			else
			{
				if ( !getGroup()->pushMissionInternal(MISSION_BOMBARD))
				{
					return getGroup()->pushMissionInternal(MISSION_ABOMBARD, pBombardCity->plot()->getX_INLINE(), pBombardCity->plot()->getY_INLINE());
				}
				else
				{
					return true;
				}
			}
		}
	}

	return false;

#if 0
	CvCity* pBombardCity;

	if (canBombard(plot()))
	{
		pBombardCity = bombardTarget(plot());
		FAssertMsg(pBombardCity != NULL, "BombardCity is not assigned a valid value");

		// do not bombard cities with no defenders
		int iDefenderStrength = pBombardCity->plot()->AI_sumStrength(NO_PLAYER, getOwnerINLINE(), DOMAIN_LAND, /*bDefensiveBonuses*/ true, /*bTestAtWar*/ true, false);
		if (iDefenderStrength == 0)
		{
			return false;
		}
		
		// do not bombard cities if we have overwelming odds
		int iAttackOdds = getGroup()->AI_attackOdds(pBombardCity->plot(), /*bPotentialEnemy*/ true);
		if ( (iAttackOdds > 95) )
		{
			return false;
		}

		// If we have reasonable odds, check for attacking without waiting for bombards
		if( (iAttackOdds >= getBBAI_SKIP_BOMBARD_BEST_ATTACK_ODDS() )
		{
			int iBase = GC.getBBAI_SKIP_BOMBARD_BASE_STACK_RATIO();
			int iComparison = getGroup()->AI_compareStacks(pBombardCity->plot(), /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);
			
			// Big troop advantage plus pretty good starting odds, don't wait to allow reinforcements
			if( iComparison > (iBase - 4*iAttackOdds) )
			{
				if( gUnitLogLevel > 2 ) logBBAI("      Stack skipping bombard of %S with compare %d and starting odds %d", pBombardCity->getName().GetCString(), iComparison, iAttackOdds);
				return false;
			}

			int iMin = GC.getBBAI_SKIP_BOMBARD_MIN_STACK_RATIO();
			bool bHasWaited = false;
			CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
			while (pUnitNode != NULL)
			{
				CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);

				if( pLoopUnit->getFortifyTurns() > 0 )
				{
					bHasWaited = true;
					break;
				}

				pUnitNode = getGroup()->nextUnitNode(pUnitNode);
			}

			// Bombard at least one turn to allow bombers/ships to get some shots in too
			if( bHasWaited && (pBombardCity->getDefenseDamage() > 0) )
			{
				int iBombardTurns = getGroup()->getBombardTurns(pBombardCity);
				if( iComparison > std::max(iMin, iBase - 3*iAttackOdds - 3*iBombardTurns) )
				{
					if( gUnitLogLevel > 2 ) logBBAI("      Stack skipping bombard of %S with compare %d, starting odds %d, and bombard turns %d", pBombardCity->getName().GetCString(), iComparison, iAttackOdds, iBombardTurns);
					return false;
				}
			}
		}

		//getGroup()->pushMission(MISSION_PILLAGE);
		getGroup()->pushMission(MISSION_BOMBARD);
		return true;
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		// RevolutionDCM - ranged bombard AI wraps standard bombard
		if (!AI_RbombardCity(pBombardCity))
		{
			// vanilla behaviour
			getGroup()->pushMission(MISSION_BOMBARD);
			return true;
		}
		// RevolutionDCM - end
/************************************************************************************************/
/* REVOLUTIONDCM                            END                                     Glider1     */
/************************************************************************************************/
	}

	return false;
#endif
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


// Returns true if a mission was pushed...
bool CvUnitAI::AI_cityAttack(int iRange, int iOddsThreshold, bool bFollow)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	FAssert(canMove());

	if (bFollow)
	{
		iSearchRange = 1;
	}
	else
	{
		iSearchRange = AI_searchRange(iRange);
	}

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot))
				{
					if (pLoopPlot->isCity() || (pLoopPlot->isCity(true, getTeam()) && pLoopPlot->isVisibleEnemyUnit(this)))
					{
						if (AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
						{
							if (!atPlot(pLoopPlot) && ((bFollow) ? canMoveOrAttackInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns, iRange) && (iPathTurns <= iRange))))
							{
								iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

								if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
								{
									if (iValue > iBestValue)
									{
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( endTurnPlot == pLoopPlot || !exposedToDanger((bFollow) ? pLoopPlot : endTurnPlot, iOddsThreshold) )
										{
											iBestValue = iValue;
											pBestPlot = ((bFollow) ? pLoopPlot : endTurnPlot);
											FAssert(!atPlot(pBestPlot));
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
	}

	return false;
}

/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
// RevolutionDCM - return this function to vanilla except for the archer bombard option
// Returns true if a mission was pushed...
bool CvUnitAI::AI_anyAttack(int iRange, int iOddsThreshold, int iMinStack, bool bAllowCities, bool bFollow)
{
	PROFILE_FUNC();
	MEMORY_TRACK();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;


	FAssert(canMove());

	if (bFollow)
	{
		iSearchRange = 1;
	}
	else
	{
		iSearchRange = AI_searchRange(iRange);
	}

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), MOVE_THROUGH_ENEMY, iSearchRange);
#endif

/************************************************************************************************/
/* DCM                                     04/19/09                                Johny Smith  */
/************************************************************************************************/
	// RevolutionDCM - return this function to vanilla except for the archer bombard option
	if (AI_rangeAttack(iRange))
	{
		return true;
	}
	// Dale - ARB: Archer Bombard START
	if (AI_Abombard())
	{
		return true;
	}
	// Dale - ARB: Archer Bombard END
/************************************************************************************************/
/* DCM                                     END                                                  */
/************************************************************************************************/
/************************************************************************************************/
/* Afforess	                  Start		 08/02/10                                               */
/*                                                                                              */
/* Fixed Borders AI                                                                             */
/************************************************************************************************/
#ifdef USE_REACHABLE_ENUMERATION
	if ( getDomainType() == DOMAIN_LAND && AI_claimForts(&plotSet, 0, iRange + 1))
#else
	if ( getDomainType() == DOMAIN_LAND && AI_claimForts(0, iRange + 1))
#endif
	{
		return true;
	}

	if (canClaimTerritory(NULL))
	{
		if (AI_guardClaimedResource())
		{
			return true;
		}

#ifdef USE_REACHABLE_ENUMERATION
		if (getDomainType() == DOMAIN_LAND && AI_claimResources(&plotSet, 0, iRange + 1))
#else
		if (getDomainType() == DOMAIN_LAND && AI_claimResources(0, iRange + 1))
#endif
		{
			return true;
		}
		m_bClaimedTerritory = false;
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	iBestValue = 0;
	pBestPlot = NULL;

#ifdef USE_REACHABLE_ENUMERATION
	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		FAssert(itr.stepDistance() <= iSearchRange);
		//	Have we already considered this plot in a previous invocation?
		int iOpaqueInfo = itr.getOpaqueInfo(ACTIVITY_ID_ANY_ATTACK);
		if ( iMinStack == 0 && bAllowCities && !bFollow )
		{
			if ( plotOpaqueInfoMatches(iOpaqueInfo, ACTIVITY_ID_ANY_ATTACK, iOddsThreshold) )
			{
				continue;
			}
		}

		pLoopPlot = itr.plot();

		if ( CvSelectionGroup::getPathGenerator()->haveRouteLength(pLoopPlot, getGroup(), 0, iPathTurns) && iPathTurns > iRange )
		{
			continue;
		}

		if( ((bAllowCities) || !(pLoopPlot->isCity(false))) )
		{
			if ( getGroup()->canMoveOrAttackInto(pLoopPlot, true) )
			{
				if ((pLoopPlot->isVisible(getTeam(),false) && pLoopPlot->isVisibleEnemyUnit(this)) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam())))
				{
					if (pLoopPlot->getNumVisibleEnemyDefenders(this) >= iMinStack)
					{
						bool bWinLikely;

						PROFILE("CvUnitAI::AI_anyAttack.FoundTarget");
						iValue = getGroup()->AI_attackOdds(pLoopPlot, true, false, &bWinLikely, iOddsThreshold);

						//	Increase value on our territory since we really want to get rid of enemies there even
						//	if it costs us a few losses
						if ( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() && bWinLikely)
						{
							iValue *= 2;
						}

						int iAdjustedOddsThreshold = AI_finalOddsThreshold(pLoopPlot, iOddsThreshold);

						if ( iMinStack == 0 && bAllowCities && !bFollow )
						{
							if ( iAdjustedOddsThreshold != 0 )
							{
								itr.setOpaqueInfo(ACTIVITY_ID_ANY_ATTACK, 1 + (100*iValue*iOddsThreshold)/iAdjustedOddsThreshold);
							}
						}

						if (iValue > iBestValue && iValue >= iAdjustedOddsThreshold)
						{
							PROFILE("CvUnitAI::AI_anyAttack.SearchPath");
							if (!atPlot(pLoopPlot) && ((bFollow) ? getGroup()->canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns, iRange) )))
							{
								PROFILE("CvUnitAI::AI_anyAttack.SuccessfulPath");

								CvPlot* endTurnPlot = getPathEndTurnPlot();

								if ( endTurnPlot == pLoopPlot || !exposedToDanger((bFollow) ? pLoopPlot : endTurnPlot, iOddsThreshold) )
								{
									iBestValue = iValue;
									pBestPlot = ((bFollow) ? pLoopPlot : endTurnPlot);
									FAssert(!atPlot(pBestPlot));

									if ( iValue > iAdjustedOddsThreshold + (100 - iAdjustedOddsThreshold)/2 )
									{
										//	Result is significantly better than we've been asked to find so cut
										//	off the search now
										break;
									}
								}
							}
						}
					}
				}
			}
		}
	}
#else
	PlotMap visited(iSearchRange, plot()->getX_INLINE(), plot()->getY_INLINE());
	BoundarySet boundary1(iSearchRange);
	BoundarySet boundary2(iSearchRange);
	
	BoundarySet* lastBoundary = &boundary1;
	BoundarySet* nextBoundary = &boundary2;

	lastBoundary->Add(plot()->getX_INLINE(), plot()->getY_INLINE());
	visited.Set(plot()->getX_INLINE(), plot()->getY_INLINE());

	for( int iDist = 1; iDist <= iSearchRange; iDist++ )
	{
		for(int j = 0; j < lastBoundary->m_boundaryLen; j++)
		{
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				pLoopPlot = plotDirection(lastBoundary->m_boundary[j].x, lastBoundary->m_boundary[j].y, ((DirectionTypes)iI));
				if ( pLoopPlot != NULL && !visited.IsSet(pLoopPlot->getX_INLINE(),pLoopPlot->getY_INLINE()) )
				{
					visited.Set(pLoopPlot->getX_INLINE(),pLoopPlot->getY_INLINE());

					if ( pLoopPlot->isCity(false) )
					{
						//	We can path through friendly cities
						if ( GET_TEAM(getTeam()).isFriendlyTerritory(pLoopPlot->getTeam()) )
						{
							nextBoundary->Add(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
							continue;
						}
					}
					if( ((bAllowCities) || !(pLoopPlot->isCity(false))) )
					{
						if ( getGroup()->canMoveOrAttackInto(pLoopPlot, true) )
						{
							if ((pLoopPlot->isVisible(getTeam(),false) && pLoopPlot->isVisibleEnemyUnit(this)) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam())))
							{
								if (pLoopPlot->getNumVisibleEnemyDefenders(this) >= iMinStack)
								{
									PROFILE("CvUnitAI::AI_anyAttack.FoundTarget");
									iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

									if (iValue > iBestValue && iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
									{
										PROFILE("CvUnitAI::AI_anyAttack.SearchPath");
										if (!atPlot(pLoopPlot) && ((bFollow) ? getGroup()->canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) )))
										{
											PROFILE("CvUnitAI::AI_anyAttack.SuccessfulPath");
											if (iPathTurns <= iRange)
											{
												PROFILE("CvUnitAI::AI_anyAttack.SuccessfulPath.InRange");

												iBestValue = iValue;
												pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
												FAssert(!atPlot(pBestPlot));
											}
										}
									}
								}
							}
							else
							{
								nextBoundary->Add(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
							}
						}
					}
				}
			}
		}

		nextBoundary = lastBoundary;
		nextBoundary->Clear();

		if ( lastBoundary == &boundary1 )
		{
			lastBoundary = &boundary2;
		}
		else
		{
			lastBoundary = &boundary1;
		}
	}
#endif

#ifdef VALIDITY_CHECK_NEW_ATTACK_SEARCH
	CvPlot*	pNewAlgorithmBestPlot = pBestPlot;
	int iNewAlgorithmBestValue = iBestValue;
	int iDX, iDY;

	iBestValue = 0;
	pBestPlot = NULL;

	{
		for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
		{
			for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
			{
				pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

				if (pLoopPlot != NULL)
				{
					if (AI_plotValid(pLoopPlot))
					{
						if( ((bAllowCities) || !(pLoopPlot->isCity(false))) )
						{
							if (pLoopPlot->isVisibleEnemyUnit(this) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam())))
							{
								if (pLoopPlot->getNumVisibleEnemyDefenders(this) >= iMinStack)
								{
									PROFILE("CvUnitAI::AI_anyAttack.FoundTarget");
									iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

									if (iValue > iBestValue && iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
									{
										PROFILE("CvUnitAI::AI_anyAttack.SearchPath");
										if (!atPlot(pLoopPlot) && ((bFollow) ? getGroup()->canMoveInto(pLoopPlot, true) : (generatePath(pLoopPlot, 0, true, &iPathTurns) )))
										{
											PROFILE("CvUnitAI::AI_anyAttack.SuccessfulPath");
											if (iPathTurns <= iRange)
											{
												PROFILE("CvUnitAI::AI_anyAttack.SuccessfulPath.InRange");

												iBestValue = iValue;
												pBestPlot = ((bFollow) ? pLoopPlot : getPathEndTurnPlot());
												FAssert(!atPlot(pBestPlot));
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	FAssert((pNewAlgorithmBestPlot == NULL) == (pBestPlot == NULL) || getDomainType() != DOMAIN_SEA);
	FAssert(iNewAlgorithmBestValue == iBestValue || getDomainType() != DOMAIN_SEA);
#endif

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
	}

	return false;
}
// RevolutionDCM end
/************************************************************************************************/
/* REVOLUTIONDCM                            END                                     Glider1     */
/************************************************************************************************/

// Returns true if a mission was pushed...
bool CvUnitAI::AI_rangeAttack(int iRange)
{
	PROFILE_FUNC();

	FAssert(canMove());

	if (!canRangeStrike())
	{
		return false;
	}

	int iSearchRange = AI_searchRange(iRange);

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;

	for (int iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (int iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if ((pLoopPlot->isVisible(getTeam(),false) && pLoopPlot->isVisibleEnemyUnit(this)) || (pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam())))
				{
					if (!atPlot(pLoopPlot) && canRangeStrikeAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						int iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		getGroup()->pushMission(MISSION_RANGE_ATTACK, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
		return true;
	}

	return false;
}

bool CvUnitAI::AI_leaveAttack(int iRange, int iOddsThreshold, int iStrengthThreshold, bool bIgnoreCity, bool bStayInBorders)
{
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvCity* pCity;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	FAssert(canMove());

	iSearchRange = iRange;
	
	iBestValue = 0;
	pBestPlot = NULL;
	
	
	pCity = plot()->getPlotCity();
	
	if ((pCity != NULL) && (pCity->getOwnerINLINE() == getOwnerINLINE()))
	{
		if (canDefend() && plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE()) <= 1)
		{
			return false;    		
		}

		int iOurStrength = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(), 0, false, false);
    	int iEnemyStrength = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(), 2, false, false);
		if (iEnemyStrength > 0)
		{
    		if (((iOurStrength * 100) / iEnemyStrength) < iStrengthThreshold)
    		{
    			return false;    		    		
    		}
		}
	}

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				//Afforess: added bStayInBorders
				if (AI_plotValid(pLoopPlot) && (!bStayInBorders || getOwnerINLINE() == pLoopPlot->getOwnerINLINE()))
				{
					//Afforess: added bIgnoreCity
					if ((pLoopPlot->isVisible(getTeam(), false) && pLoopPlot->isVisibleEnemyUnit(this)) || (!bIgnoreCity && pLoopPlot->isCity() && AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot)))
					{
						//	Koshling - removed this check because it prevents defenceless stacks being attacked (why wouldn't you?)
						//if (pLoopPlot->getNumVisibleEnemyDefenders(this) > 0)
						{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      06/27/10                                jdog5000      */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
							if (!atPlot(pLoopPlot) && (generatePath(pLoopPlot, 0, true, &iPathTurns, iRange)))
							{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
								iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

								if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
								{
									if (iValue > iBestValue)
									{
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, iOddsThreshold) )
										{
											iBestValue = iValue;
											pBestPlot = endTurnPlot;
											FAssert(!atPlot(pBestPlot));
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0);
	}

	return false;
	
}

int CvUnitAI::AI_blockadeValue(CvPlot* pLoopPlot, CvCity* pCity, CvPlot*& endTurnPlot) const
{
	int iValue = 0;
	int	iPathTurns;

	if (generatePath(pLoopPlot, 0, true, &iPathTurns))
	{
		PROFILE("CvUnitAI::AI_blockade.PathChecked");

		iValue = 1;

		iValue += std::min(pCity->getPopulation(), pCity->countNumWaterPlots());

		iValue += GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pCity->plot());

		iValue += (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), MISSIONAI_ASSAULT, getGroup(), 2) * 3);

		if (getGroup()->canBombard(pLoopPlot))
		{
			iValue *= 2;
		}

		iValue *= 1000;

		iValue /= (iPathTurns + 1);
		
		if (iPathTurns == 1)
		{
			//Prefer to have movement remaining to Bombard + Plunder
			iValue *= 1 + std::min(2, (getPathMovementRemaining()+GC.getMOVE_DENOMINATOR()-1)/GC.getMOVE_DENOMINATOR());
		}

		// if not at war with this plot owner, then devalue plot if we already inside this owner's borders
		// (because declaring war will pop us some unknown distance away)
		if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
		{
			iValue /= 10;
		}

		endTurnPlot = getPathEndTurnPlot();
	}

	return iValue;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_blockade()
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pBestCity;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestBlockadePlot;
	int iValue;
	int iBestValue;
	int iBestRange;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestBlockadePlot = NULL;

	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	for(int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if ( iI == getOwnerINLINE() || !GET_PLAYER((PlayerTypes)iI).isAlive() || GET_PLAYER((PlayerTypes)iI).isBarbarian())
		{
			continue;
		}
		
		TeamTypes eTeam = GET_PLAYER((PlayerTypes)iI).getTeam();

		if ( !isEnemy(eTeam) && GET_TEAM(getTeam()).AI_getWarPlan(eTeam) == NO_WARPLAN )
		{
			continue;
		}

		int iLoopCity;

		for(pCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoopCity); pCity != NULL; pCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoopCity))
		{
			if ( !pCity->isRevealed(getTeam(),false) )
			{
				continue;
			}

			if (!pCity->isCoastal(GC.getMIN_WATER_SIZE_FOR_OCEAN()))
			{
				continue;
			}

			int iJ;
			for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
			{
				pLoopPlot = plotDirection(pCity->plot()->getX_INLINE(), pCity->plot()->getY_INLINE(), ((DirectionTypes)iJ));

				if ( pLoopPlot != NULL &&
					 pLoopPlot->isRevealed(getTeam(),false) &&
					 pLoopPlot->getWorkingCity() == pCity &&
					 (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this)) &&
					 canPlunder(pLoopPlot) &&
					 plotSet.find(pLoopPlot) != plotSet.end() &&
					 GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BLOCKADE, getGroup(), 2) == 0)
				{
					break;
				}
			}

			if ( pLoopPlot == NULL )
			{
				continue;
			}

			CvReachablePlotSet::const_iterator itr =  plotSet.find(pLoopPlot);
			if ( iBestValue > 0 && itr.stepDistance() > 2*iBestRange )
			{
				continue;
			}

			if (potentialWarAction(pLoopPlot))
			{
				FAssert(isEnemy(pCity->getTeam()) || GET_TEAM(getTeam()).AI_getWarPlan(pCity->getTeam()) != NO_WARPLAN);

				{
					CvPlot* endTurnPlot;

					PROFILE("CvUnitAI::AI_blockade.Possibility");

					iValue = AI_blockadeValue(pLoopPlot, pCity, endTurnPlot);

					if (iValue > iBestValue)
					{
						if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 70) )
						{
							iBestValue = iValue;
							iBestRange = itr.stepDistance();
							pBestPlot = endTurnPlot;
							pBestCity = pCity;
							pBestBlockadePlot = pLoopPlot;
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestBlockadePlot != NULL))
	{
		FAssert(canPlunder(pBestBlockadePlot));
		if (atPlot(pBestBlockadePlot) && !isEnemy(pBestBlockadePlot->getTeam(), pBestBlockadePlot))
		{
			getGroup()->groupDeclareWar(pBestBlockadePlot, true);
		}
		
		if (atPlot(pBestBlockadePlot))
		{
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
			// RevolutionDCM - new field bombard ai
			// Dale - RB: Field Bombard START
			//if (canRBombard(plot()))
			//{
			//	getGroup()->pushMission(MISSION_RBOMBARD, pBestBlockadePlot->getX_INLINE(), pBestBlockadePlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
			//}
			// Dale - RB: Field Bombard END
/************************************************************************************************/
/* REVOLUTIONDCM                             END                                    Glider1     */
/************************************************************************************************/
			if (getGroup()->canBombard(plot()))
			{
				getGroup()->pushMission(MISSION_BOMBARD, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
			}

			getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
			
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_pirateBlockade()
{
	PROFILE_FUNC();
	
	int iPathTurns;
	int iValue;
	int iI;
	
	std::vector<int> aiDeathZone(GC.getMapINLINE().numPlotsINLINE(), 0);
#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);
#endif
	
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#ifdef USE_REACHABLE_ENUMERATION
		if (plotSet.find(pLoopPlot) != plotSet.end())
#else
		if (AI_plotValid(pLoopPlot) && (pLoopPlot->area() == area() || (pLoopPlot->isCity() && pLoopPlot->isAdjacentToArea(area()))))
#endif
		{
			if (pLoopPlot->isOwned() && (pLoopPlot->getTeam() != getTeam()))
			{
				int iBestHostileMoves = 0;
				CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
				while (pUnitNode != NULL)
				{
					CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
					pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
					if (isEnemy(pLoopUnit->getTeam(), pLoopUnit->plot()))
					{
						if (pLoopUnit->getDomainType() == DOMAIN_SEA && !pLoopUnit->isInvisible(getTeam(), false))
						{
							if (pLoopUnit->canAttack())
							{
								if (pLoopUnit->currEffectiveStr(NULL, NULL, NULL) > currEffectiveStr(pLoopPlot, pLoopUnit, NULL))
								{
									//Fuyu: No (rail)roads on water, always movement cost 1. Rounding up of course
									iBestHostileMoves = std::max(iBestHostileMoves, (pLoopUnit->getMoves() + GC.getMOVE_DENOMINATOR() - 1) / GC.getMOVE_DENOMINATOR());									
								}
							}
						}
					}
				}
				if (iBestHostileMoves > 0)
				{
					for (int iX = -iBestHostileMoves; iX <= iBestHostileMoves; iX++)
					{
						for (int iY = -iBestHostileMoves; iY <= iBestHostileMoves; iY++)
						{
							CvPlot * pRangePlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
							if (pRangePlot != NULL)
							{
								aiDeathZone[GC.getMap().plotNumINLINE(pRangePlot->getX_INLINE(), pRangePlot->getY_INLINE())]++;
							}
						}
					}
				}
			}
		}
	}
	
	bool bIsInDanger = aiDeathZone[GC.getMap().plotNumINLINE(getX_INLINE(), getY_INLINE())] > 0;
	bool bNeedsHeal = (getDamage() > 0);
	bool bHasTerrainDamage = (plot()->getTerrainTurnDamage(getGroup()) > 0 || plot()->getFeatureTurnDamage() > 0);	

	if (!bIsInDanger)
	{
		if (bNeedsHeal)
		{
			if ((!plot()->isOwned() && !plot()->isAdjacentOwned()) || getDamage() > 25)
			{
				//	If we only have damage explained by teh curretn plot for one turn
				//	don't use that as an excuse to immediately turn around and go hide
				//	in a city!
				if ( !bHasTerrainDamage || getDamage() > (plot()->getTerrainTurnDamage(getGroup()) + plot()->getFeatureTurnDamage()) )
				{
					if (AI_retreatToCity(false, false, 1 + getDamage() / 20))
					{
						return true;
					}
				}

				if ( !bHasTerrainDamage )
				{
					getGroup()->pushMission(MISSION_SKIP);
					return true;
				}
			}
		}
	}
	
	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestBlockadePlot = NULL;
	bool bBestIsForceMove = false;
	bool bBestIsMove = false;
	
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

#ifdef USE_REACHABLE_ENUMERATION
		if (plotSet.find(pLoopPlot) != plotSet.end())
#else
		if (AI_plotValid(pLoopPlot) && pLoopPlot->area() == area())
#endif
		{
			if (!pLoopPlot->isVisible(getTeam(),false) && !pLoopPlot->isVisibleEnemyUnit(this) && canPlunder(pLoopPlot))
			{
				if (GC.getGame().getSorenRandNum(4, "AI Pirate Blockade") == 0)
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BLOCKADE, getGroup(), 3) == 0)
					{
						int iBlockadedCount = 0;
						int iPopulationValue = 0;
						int iRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE") - 1;
						for (int iX = -iRange; iX <= iRange; iX++)
						{
							for (int iY = -iRange; iY <= iRange; iY++)
							{
								CvPlot* pRangePlot = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iX, iY);
								if (pRangePlot != NULL)
								{
									bool bPlotBlockaded = false;
									if (pRangePlot->isWater() && pRangePlot->isOwned() && isEnemy(pRangePlot->getTeam(), pLoopPlot))
									{
										bPlotBlockaded = true;
										iBlockadedCount += pRangePlot->getBlockadedCount(pRangePlot->getTeam());
									}
									
									if (!bPlotBlockaded)
									{
										CvCity* pPlotCity = pRangePlot->getPlotCity();
										if (pPlotCity != NULL)
										{
											if (isEnemy(pPlotCity->getTeam(), pLoopPlot))															
											{
												int iCityValue = 3 + pPlotCity->getPopulation();
												iCityValue *= (atWar(getTeam(), pPlotCity->getTeam()) ? 1 : 3);
												if (GET_PLAYER(pPlotCity->getOwnerINLINE()).isNoForeignTrade())
												{
													iCityValue /= 2;
												}
												iPopulationValue += iCityValue;
												
											}
										}
									}
								}
							}
						}
						iValue = iPopulationValue;
						
						iValue *= 1000;
						
						iValue /= 16 + iBlockadedCount;
						
						if (atPlot(pLoopPlot))
						{
							iValue *= 3;
						}
						
						int iDeath = aiDeathZone[GC.getMap().plotNumINLINE(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE())];
						
						bool bForceMove = false;
						if (iDeath)
						{
							iValue /= 10;
						}

						int iBestEstimateValue = iValue;

						CvReachablePlotSet::const_iterator itr =  plotSet.find(pLoopPlot);

						FAssert(itr != plotSet.end());
						int iMinTurns = itr.stepDistance()/baseMoves() + 1;

						if ( iMinTurns <= 2 && !pLoopPlot->isAdjacentOwned() && bIsInDanger && iPopulationValue== 0)
						{
							iBestEstimateValue += 5000;
						}
						else
						{
							iBestEstimateValue /= iMinTurns + 1;
						}

						if ( iMinTurns == 1 )
						{
							iBestEstimateValue *= 2;
						}

						if (iBestEstimateValue > iBestValue && generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
						{
							if (!iDeath && bIsInDanger && (iPathTurns <= 2) && (0 == iPopulationValue))
							{
								if (getPathMovementRemaining() == 0)
								{
									if (!pLoopPlot->isAdjacentOwned())
									{
										int iRand = GC.getGame().getSorenRandNum(2500, "AI Pirate Retreat");
										iValue += iRand;
										if (iRand > 1000)
										{
											iValue += GC.getGame().getSorenRandNum(2500, "AI Pirate Retreat");
											bForceMove = true;
										}
									}
								}
							}
							
							if (!bForceMove)
							{
								iValue /= iPathTurns + 1;
							}
							
							bool bMove = (iPathTurns == 1) && (getPathMovementRemaining() > 0);
							if (bMove && !atPlot(pLoopPlot))
							{
								iValue *= 2;
							}

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = bForceMove ? pLoopPlot : getPathEndTurnPlot();
								pBestBlockadePlot = pLoopPlot;
								bBestIsForceMove = bForceMove;
								bBestIsMove = bMove;
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestBlockadePlot != NULL))
	{
		FAssert(canPlunder(pBestBlockadePlot));

		if (atPlot(pBestBlockadePlot))
		{
			getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));

			if ( bNeedsHeal )
			{
				CvPlot*	pBestStopAndHealPlot = pBestPlot;

				//	Examine plots we move through in this turn and see if any is suitable to stop and heal in
				generatePath(pBestPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns);
				CvPath::const_iterator itr = getGroup()->getPath().begin();

				while ( itr != getGroup()->getPath().end() )
				{
					CvPlot*	pPlot = itr.plot();

					bool bIsInDanger = aiDeathZone[GC.getMap().plotNumINLINE(pPlot->getX_INLINE(), pPlot->getY_INLINE())] > 0;
					bool bHasTerrainDamage = (pPlot->getTerrainTurnDamage(getGroup()) > 0 || pPlot->getFeatureTurnDamage() > 0);	

					//	If an intermediary plot is one that the heal decsion logic (near the start of this method)
					//	would choose to heal in, then just stop there on our way
					if ((!pPlot->isOwned() && !pPlot->isAdjacentOwned()) || getDamage() > 25)
					{
						if ( !bIsInDanger && ! bHasTerrainDamage )
						{
							pBestStopAndHealPlot = pPlot;
						}
					}

					if ( pPlot == pBestPlot )
					{
						break;
					}

					++itr;
				}

				pBestPlot = pBestStopAndHealPlot;
			}

			if (bBestIsForceMove)
			{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/01/09                                jdog5000      */
/*                                                                                              */
/* Pirate AI                                                                                    */
/************************************************************************************************/
/* original bts code
				getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
*/
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/				
			}
			else
			{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/01/09                                jdog5000      */
/*                                                                                              */
/* Pirate AI                                                                                    */
/************************************************************************************************/
/* original bts code
				getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
*/
				if ( getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_BLOCKADE, pBestBlockadePlot))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
				{
					if (bBestIsMove)
					{
						getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BLOCKADE, pBestBlockadePlot);
					}
					return true;
				}
			}
		}
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_seaBombardRange(int iMaxRange)
{
	PROFILE_FUNC();
	
	// cached values
	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
	CvPlot* pPlot = plot();
	CvSelectionGroup* pGroup = getGroup();
	
	// can any unit in this group bombard?
	bool bHasBombardUnit = false;
	bool bBombardUnitCanBombardNow = false;
	CLLNode<IDInfo>* pUnitNode = pGroup->headUnitNode();
	while (pUnitNode != NULL && !bBombardUnitCanBombardNow)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pGroup->nextUnitNode(pUnitNode);

		if (pLoopUnit->bombardRate() > 0)
		{
			bHasBombardUnit = true;

			if (pLoopUnit->canMove() && !pLoopUnit->isMadeAttack())
			{
				bBombardUnitCanBombardNow = true;
			}
		}
	}

	if (!bHasBombardUnit)
	{
		return false;
	}

	// best match
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestBombardPlot = NULL;
	int iBestValue = 0;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, iMaxRange);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		{
			CvPlot* pLoopPlot = itr.plot();
#else
		// iterate over plots at each range
	for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
	{
		for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
		{
			CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
#endif
			if (pLoopPlot != NULL /*&& AI_plotValid(pLoopPlot)*/)
			{
				CvCity* pBombardCity = bombardTarget(pLoopPlot);

				if (pBombardCity != NULL && isEnemy(pBombardCity->getTeam(), pLoopPlot) && pBombardCity->getDefenseDamage() < GC.getMAX_CITY_DEFENSE_DAMAGE())
				{
					int iPathTurns;
					if (generatePath(pLoopPlot, 0, true, &iPathTurns))
					{
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						6/24/08				jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
						// Loop construction doesn't guarantee we can get there anytime soon, could be on other side of narrow continent
						if( iPathTurns <= (1 + iMaxRange/std::max(1, baseMoves())) )
						{
							// Check only for supporting our own ground troops first, if none will look for another target
							int iValue = (kPlayer.AI_plotTargetMissionAIs(pBombardCity->plot(), MISSIONAI_ASSAULT, NULL, 2) * 3);
							iValue += (kPlayer.AI_adjacentPotentialAttackers(pBombardCity->plot(), true));
							
							if (iValue > 0)
							{
								iValue *= 1000;

								iValue /= (iPathTurns + 1);
								
								if (iPathTurns == 1)
								{
									//Prefer to have movement remaining to Bombard + Plunder
									iValue *= 1 + std::min(2, getPathMovementRemaining());
								}

								if (iValue > iBestValue)
								{
									CvPlot* endTurnPlot = getPathEndTurnPlot();

									if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 70) )
									{
										iBestValue = iValue;
										pBestPlot = endTurnPlot;
										pBestBombardPlot = pLoopPlot;
									}
								}
							}
						}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD							END							*/
/********************************************************************************/
					}
				}
			}
		}
	}

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						6/24/08				jdog5000	*/
/* 																			*/
/* 	Naval AI																*/
/********************************************************************************/
	// If no troops of ours to support, check for other bombard targets
	if( (pBestPlot == NULL) && (pBestBombardPlot == NULL) )
	{
		if( (AI_getUnitAIType() != UNITAI_ASSAULT_SEA) )
		{
			for (int iDX = -(iMaxRange); iDX <= iMaxRange; iDX++)
			{
				for (int iDY = -(iMaxRange); iDY <= iMaxRange; iDY++)
				{
					CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
					
					if (pLoopPlot != NULL && AI_plotValid(pLoopPlot))
					{
						CvCity* pBombardCity = bombardTarget(pLoopPlot);

						// Consider city even if fully bombarded, causes ship to camp outside blockading instead of twitching between
						// cities after bombarding to 0
						if (pBombardCity != NULL && isEnemy(pBombardCity->getTeam(), pLoopPlot) && pBombardCity->getTotalDefense(false) > 0)
						{
							int iPathTurns;
							if (generatePath(pLoopPlot, 0, true, &iPathTurns))
							{	
								// Loop construction doesn't guarantee we can get there anytime soon, could be on other side of narrow continent
								if( iPathTurns <= 1 + iMaxRange/std::max(1, baseMoves()) )
								{
									int iValue = std::min(20,pBombardCity->getDefenseModifier(false)/2); 

									// Inclination to support attacks by others
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
									//if( GET_PLAYER(pBombardCity->getOwnerINLINE()).AI_getPlotDanger(pBombardCity->plot(), 2, false) > 0 )
									if( GET_PLAYER(pBombardCity->getOwnerINLINE()).AI_getAnyPlotDanger(pBombardCity->plot(), 2, false) )
									{
										iValue += 60;
									}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

									// Inclination to bombard a different nearby city to extend the reach of blockade
									if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pBombardCity->plot(), MISSIONAI_BLOCKADE, getGroup(), 3) == 0 )
									{
										iValue += 35 + pBombardCity->getPopulation();
									}

									// Small inclination to bombard area target, not too large so as not to tip our hand
									if( pBombardCity == pBombardCity->area()->getTargetCity(getOwnerINLINE()) )
									{
										iValue += 10;
									}
										
									if (iValue > 0)
									{
										iValue *= 1000;

										iValue /= (iPathTurns + 1);
										
										if (iPathTurns == 1)
										{
											//Prefer to have movement remaining to Bombard + Plunder
											iValue *= 1 + std::min(2, (getPathMovementRemaining()+GC.getMOVE_DENOMINATOR()-1)/GC.getMOVE_DENOMINATOR());
										}

										if (iValue > iBestValue)
										{
											iBestValue = iValue;
											pBestPlot = getPathEndTurnPlot();
											pBestBombardPlot = pLoopPlot;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD							END							*/
	/********************************************************************************/
	
	if ((pBestPlot != NULL) && (pBestBombardPlot != NULL))
	{
		if (atPlot(pBestBombardPlot))
		{
			// if we are at the plot from which to bombard, and we have a unit that can bombard this turn, do it
			if (bBombardUnitCanBombardNow && pGroup->canBombard(pBestBombardPlot))
			{
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
				// RevolutionDCM - sea bombard AI formally DCM 1.7 AI_RbombardCity()
				// Dale - RB: Field Bombard START
				//if (AI_RbombardCity())
				//{
				//	return;
				//}
				if (AI_RbombardNaval())
				{
					return true;
				}
				// Dale - RB: Field Bombard END
				
				// RevolutionDCM - bug fix 04/07/2009 DCM 1.7 accidently omits this line - thanks Arian for reporting
				getGroup()->pushMission(MISSION_BOMBARD, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
/************************************************************************************************/
/* REVOLUTIONDCM                            END                                     Glider1     */
/************************************************************************************************/

				// if city bombarded enough, wake up any units that were waiting to bombard this city
				CvCity* pBombardCity = bombardTarget(pBestBombardPlot); // is NULL if city cannot be bombarded any more
				if (pBombardCity == NULL || pBombardCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE()*5)/6))
				{
					kPlayer.AI_wakePlotTargetMissionAIs(pBestBombardPlot, MISSIONAI_BLOCKADE, getGroup());
				}
			}
			// otherwise, skip until next turn, when we will surely bombard
			else if (canPlunder(pBestBombardPlot))
			{
				getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
			}
			else
			{
				getGroup()->pushMission(MISSION_SKIP);
			}

			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BLOCKADE, pBestBombardPlot);
		}
	}

	return false;
}



// Returns true if a mission was pushed...
bool CvUnitAI::AI_pillage(int iBonusValueThreshold)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestPillagePlot;
	int iPathTurns;
	int iValue;
	int iBestValue;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestPillagePlot = NULL;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	int iI;
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		if (/*AI_plotValid(pLoopPlot) &&*/ !(pLoopPlot->isBarbarian()) && pLoopPlot->area() == area())
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/22/10                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
			//if (potentialWarAction(pLoopPlot))
			if( pLoopPlot->isOwned() && isEnemy(pLoopPlot->getTeam(),pLoopPlot) )
			{
			    CvCity * pWorkingCity = pLoopPlot->getWorkingCity();

			    if (pWorkingCity != NULL)
			    {
                    if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && getGroup()->canPillage(pLoopPlot))
                    {
                        if (pLoopPlot->isRevealed(getTeam(),false) &&
							(!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this)))
                        {
                            if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup(), 1) == 0)
                            {
								iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);
								iValue *= 1000;

								// if not at war with this plot owner, then devalue plot if we already inside this owner's borders
								// (because declaring war will pop us some unknown distance away)
								if (getCombatOwner(pLoopPlot->getTeam(),pLoopPlot) == getOwnerINLINE() &&
									!isEnemy(pLoopPlot->getTeam()) &&
									plot()->getTeam() == pLoopPlot->getTeam())
								{
									iValue /= 10;
								}

								if( iValue > iBestValue )
								{
									if (generatePath(pLoopPlot, 0, true, &iPathTurns))
									{
										iValue /= (iPathTurns + 1);

										if (iValue > iBestValue)
										{
											CvPlot* endTurnPlot = getPathEndTurnPlot();

											if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 70) )
											{
												iBestValue = iValue;
												pBestPlot = endTurnPlot;
												pBestPillagePlot = pLoopPlot;
											}
										}
									}
                                }
							}
                        }
                    }
			    }
			}
		}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	}

	if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
	{
		if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
		{
			//getGroup()->groupDeclareWar(pBestPillagePlot, true);
			// rather than declare war, just find something else to do, since we may already be deep in enemy territory
			return false;
		}
		
		if (atPlot(pBestPillagePlot))
		{
			if (isEnemy(pBestPillagePlot->getTeam()))
			{
				getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
				return true;
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
		}
	}

	return false;
}

bool CvUnitAI::AI_canPillage(CvPlot& kPlot) const
{
	if (isEnemy(kPlot.getTeam(), &kPlot))
	{
		return true;
	}

	if (!kPlot.isOwned())
	{
		bool bPillageUnowned = true;

		for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS && bPillageUnowned; ++iPlayer)
		{
			int iIndx;
			CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iPlayer);
			if (!isEnemy(kLoopPlayer.getTeam(), &kPlot))
			{
				for (CvCity* pCity = kLoopPlayer.firstCity(&iIndx); NULL != pCity; pCity = kLoopPlayer.nextCity(&iIndx))
				{
					if (kPlot.getPlotGroup((PlayerTypes)iPlayer) == pCity->plot()->getPlotGroup((PlayerTypes)iPlayer))
					{
						bPillageUnowned = false;
						break;
					}

				}
			}
		}

		if (bPillageUnowned)
		{
			return true;
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_pillageRange(int iRange, int iBonusValueThreshold)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestPillagePlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;

	iSearchRange = AI_searchRange(iRange);

	iBestValue = 0;
	pBestPlot = NULL;
	pBestPillagePlot = NULL;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, iSearchRange);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();

		//	Have we already considered this plot in a previous invocation?
		int iOpaqueInfo = itr.getOpaqueInfo(ACTIVITY_ID_PILLAGE);
		if ( plotOpaqueInfoMatches(iOpaqueInfo, ACTIVITY_ID_PILLAGE, iBonusValueThreshold+1) )
		{
			continue;
		}

		itr.setOpaqueInfo(ACTIVITY_ID_PILLAGE, iBonusValueThreshold+1);

		if ((!(pLoopPlot->isBarbarian()) || !GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PILLAGE_AVOID_BARBARIAN_CITIES)))
		{
			if (potentialWarAction(pLoopPlot))
			{
				CvCity * pWorkingCity = pLoopPlot->getWorkingCity();

				if (pWorkingCity != NULL)
				{
					if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && getGroup()->canPillage(pLoopPlot))
					{
						if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
						{
							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
							{
								iValue = 1000*AI_pillageValue(pLoopPlot, iBonusValueThreshold);

								// if not at war with this plot owner, then devalue plot if we already inside this owner's borders
								// (because declaring war will pop us some unknown distance away)
								if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
								{
									iValue /= 10;
								}

								//	TODO - should really evaluate how dangerous the target plot is and take acount of that
								//	in both the value and whether to even consider it.  Factors to take account of:
								//		Defense modifier
								//		Adjacency damage
								//		Enemy stacks in strenght relationship to our own

								if ( iValue > iBestValue && generatePath(pLoopPlot, 0, true, &iPathTurns, iRange))
								{
									if (getPathMovementRemaining() == 0)
									{
										iPathTurns++;
									}

									if (iPathTurns <= iRange)
									{
										iValue /= (iPathTurns + 1);

										if (iValue > iBestValue)
										{
											CvPlot* endTurnPlot = getPathEndTurnPlot();

											if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 70) )
											{
												iBestValue = iValue;
												pBestPlot = endTurnPlot;
												pBestPillagePlot = pLoopPlot;

												FAssert(pBestPlot == pBestPillagePlot || !atPlot(pBestPlot));
											}
										}
									}
								}
								else
								{
									//	Actually out of range so not really markable as searched (if we'd already
									//	found a pathable candidate it wont matter anyway since this routine will
									//	push a mission)
									itr.setOpaqueInfo(ACTIVITY_ID_PILLAGE, 0);
								}
							}
						}
					}
				}
			}
		}
	}
#else
	PlotMap visited(iSearchRange, plot()->getX_INLINE(), plot()->getY_INLINE());
	BoundarySet boundary1(iSearchRange);
	BoundarySet boundary2(iSearchRange);
	
	BoundarySet* lastBoundary = &boundary1;
	BoundarySet* nextBoundary = &boundary2;

	lastBoundary->Add(plot()->getX_INLINE(), plot()->getY_INLINE());
	//	Don't set our start spot as vistied since we wan to consider pillaging it - easiest way is to
	//	let the second iteration's boundary pick it up
	//visited.Set(plot()->getX_INLINE(), plot()->getY_INLINE());

	for( int iDist = 1; iDist <= iSearchRange; iDist++ )
	{
		for(int j = 0; j < lastBoundary->m_boundaryLen; j++)
		{
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				pLoopPlot = plotDirection(lastBoundary->m_boundary[j].x, lastBoundary->m_boundary[j].y, ((DirectionTypes)iI));

				if ( pLoopPlot != NULL && !visited.IsSet(pLoopPlot->getX_INLINE(),pLoopPlot->getY_INLINE()) )
				{
					visited.Set(pLoopPlot->getX_INLINE(),pLoopPlot->getY_INLINE());

					if ( AI_plotValid(pLoopPlot) )
					{
						if ( atPlot(pLoopPlot) || getGroup()->canMoveInto(pLoopPlot) )
						{
							nextBoundary->Add(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());

							if ((!(pLoopPlot->isBarbarian()) || !GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PILLAGE_AVOID_BARBARIAN_CITIES)))
							{
								if (potentialWarAction(pLoopPlot))
								{
									CvCity * pWorkingCity = pLoopPlot->getWorkingCity();

									if (pWorkingCity != NULL)
									{
										if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && canPillage(pLoopPlot))
										{
											if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
											{
												if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
												{
													iValue = 1000*AI_pillageValue(pLoopPlot, iBonusValueThreshold);

													// if not at war with this plot owner, then devalue plot if we already inside this owner's borders
													// (because declaring war will pop us some unknown distance away)
													if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
													{
														iValue /= 10;
													}

													if ( iValue > iBestValue && generatePath(pLoopPlot, 0, true, &iPathTurns))
													{
														if (getPathLastNode()->m_iData1 == 0)
														{
															iPathTurns++;
														}

														if (iPathTurns <= iRange)
														{
															iValue /= (iPathTurns + 1);

															if (iValue > iBestValue)
															{
																iBestValue = iValue;
																pBestPlot = getPathEndTurnPlot();
																pBestPillagePlot = pLoopPlot;
															}
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}

		nextBoundary = lastBoundary;
		nextBoundary->Clear();

		if ( lastBoundary == &boundary1 )
		{
			lastBoundary = &boundary2;
		}
		else
		{
			lastBoundary = &boundary1;
		}
	}
#endif

#ifdef VALIDITY_CHECK_NEW_ATTACK_SEARCH
	CvPlot*	pNewAlgorithmBestPlot = pBestPlot;
	int iNewAlgorithmBestValue = iBestValue;
	int iDX, iDY;

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
/************************************************************************************************/
/* Afforess	                  Start		 06/11/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
/*
				if (AI_plotValid(pLoopPlot) && !(pLoopPlot->isBarbarian()))
*/
				if (AI_plotValid(pLoopPlot) && (!(pLoopPlot->isBarbarian()) || !GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PILLAGE_AVOID_BARBARIAN_CITIES)))
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
				{
					if (potentialWarAction(pLoopPlot))
					{
                        CvCity * pWorkingCity = pLoopPlot->getWorkingCity();

                        if (pWorkingCity != NULL)
                        {
                            if (!(pWorkingCity == area()->getTargetCity(getOwnerINLINE())) && canPillage(pLoopPlot))
                            {
                                if (!(pLoopPlot->isVisibleEnemyUnit(this)))
                                {
                                    if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup()) == 0)
                                    {
                                        if (generatePath(pLoopPlot, 0, true, &iPathTurns))
                                        {
                                            if (getPathLastNode()->m_iData1 == 0)
                                            {
                                                iPathTurns++;
                                            }

                                            if (iPathTurns <= iRange)
                                            {
                                                iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);

                                                iValue *= 1000;

                                                iValue /= (iPathTurns + 1);

												// if not at war with this plot owner, then devalue plot if we already inside this owner's borders
												// (because declaring war will pop us some unknown distance away)
												if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
												{
													iValue /= 10;
												}

                                                if (iValue > iBestValue)
                                                {
                                                    iBestValue = iValue;
                                                    pBestPlot = getPathEndTurnPlot();
                                                    pBestPillagePlot = pLoopPlot;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
					}
				}
			}
		}
	}

	FAssert((pNewAlgorithmBestPlot == NULL) == (pBestPlot == NULL) || getDomainType() != DOMAIN_SEA);
	FAssert(iNewAlgorithmBestValue == iBestValue || getDomainType() != DOMAIN_SEA);
#endif

	if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
	{
		if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
		{
			//getGroup()->groupDeclareWar(pBestPillagePlot, true);
			// rather than declare war, just find something else to do, since we may already be deep in enemy territory
			return false;
		}
		
		if (atPlot(pBestPillagePlot))
		{
			if (isEnemy(pBestPillagePlot->getTeam()))
			{
				getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
				return true;
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
		}
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_found()
{
	PROFILE_FUNC();
//
//	CvPlot* pLoopPlot;
//	CvPlot* pBestPlot;
//	CvPlot* pBestFoundPlot;
//	int iPathTurns;
//	int iValue;
//	int iBestValue;
//	int iI;
//
//	iBestValue = 0;
//	pBestPlot = NULL;
//	pBestFoundPlot = NULL;
//
//	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
//	{
//		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
//
//		if (AI_plotValid(pLoopPlot) && (pLoopPlot != plot() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopPlot, 1) <= pLoopPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE())))
//		{
//			if (canFound(pLoopPlot))
//			{
//				iValue = pLoopPlot->getFoundValue(getOwnerINLINE());
//
//				if (iValue > 0)
//				{
//					if (!(pLoopPlot->isVisibleEnemyUnit(this)))
//					{
//						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 3) == 0)
//						{
//							if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
//							{
//								iValue *= 1000;
//
//								iValue /= (iPathTurns + 1);
//
//								if (iValue > iBestValue)
//								{
//									iBestValue = iValue;
//									pBestPlot = getPathEndTurnPlot();
//									pBestFoundPlot = pLoopPlot;
//								}
//							}
//						}
//					}
//				}
//			}
//		}
//	}

	int iPathTurns;
	int iValue;
	int iBestFoundValue = 0;
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestFoundPlot = NULL;

	for (int iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
	{
		CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/23/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/
/* orginal BTS code
		if (pCitySitePlot->getArea() == getArea())
*/
		if (pCitySitePlot->getArea() == getArea() || canMoveAllTerrain())
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		{
			if (canFound(pCitySitePlot))
			{
				if (!pCitySitePlot->isVisible(getTeam(),false) || !pCitySitePlot->isVisibleEnemyUnit(this))
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup()) == 0)
					{
						if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_GUARD_CITY) > 0)
						{
							if (generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
							{
								iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
								iValue *= 1000;
								iValue /= (iPathTurns + 1);
								if (iValue > iBestFoundValue)
								{
									CvPlot* endTurnPlot = getPathEndTurnPlot();

									if ( endTurnPlot == pCitySitePlot || !exposedToDanger(endTurnPlot, 80) )
									{
										iBestFoundValue = iValue;
										pBestPlot = endTurnPlot;
										pBestFoundPlot = pCitySitePlot;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
	{
		if (atPlot(pBestFoundPlot))
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/02/09                                jdog5000      */
/*                                                                                              */
/* AI logging                                                                                   */
/************************************************************************************************/
			if( gUnitLogLevel >= 2 )
			{
				logBBAI("    Settler founding at best found plot %d, %d", pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE());
			}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			getGroup()->pushMission(MISSION_FOUND, -1, -1, 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
			return true;
		}
		else
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/02/09                                jdog5000      */
/*                                                                                              */
/* AI logging                                                                                   */
/************************************************************************************************/
			if( gUnitLogLevel >= 2 )
			{
				logBBAI("    Settler heading for best found plot %d, %d", pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE());
			}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pBestFoundPlot);
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_foundRange(int iRange, bool bFollow)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestFoundPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iSearchRange = AI_searchRange(iRange);

	iBestValue = 0;
	pBestPlot = NULL;
	pBestFoundPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot) && (pLoopPlot != plot() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopPlot, 1) <= pLoopPlot->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE())))
				{
					if (canFound(pLoopPlot))
					{
						iValue = pLoopPlot->getFoundValue(getOwnerINLINE());

						if (iValue > iBestValue)
						{
							if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
							{
								if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 3) == 0)
								{
									if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns, iRange))
									{
										if (iPathTurns <= iRange)
										{
											CvPlot* endTurnPlot = getPathEndTurnPlot();

											if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 80) )
											{
												iBestValue = iValue;
												pBestPlot = endTurnPlot;
												pBestFoundPlot = pLoopPlot;
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
	{
		if (atPlot(pBestFoundPlot))
		{
			getGroup()->pushMission(MISSION_FOUND, -1, -1, 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
			return true;
		}
		else if (!bFollow)
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_FOUND, pBestFoundPlot);
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_assaultSeaTransport(bool bBarbarian)
{
	PROFILE_FUNC();

	bool bIsAttackCity = (getUnitAICargo(UNITAI_ATTACK_CITY) > 0);
	
	FAssert(getGroup()->hasCargo());
	//FAssert(bIsAttackCity || getGroup()->getUnitAICargo(UNITAI_ATTACK) > 0);

	if (!canCargoAllMove())
	{
		return false;
	}

	std::vector<CvUnit*> aGroupCargo;
	CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
	while (pUnitNode != NULL)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = plot()->nextUnitNode(pUnitNode);
		CvUnit* pTransport = pLoopUnit->getTransportUnit();
		if (pTransport != NULL && pTransport->getGroup() == getGroup())
		{
			aGroupCargo.push_back(pLoopUnit);
		}
	}

	int iCargo = getGroup()->getCargo();
	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestAssaultPlot = NULL;
#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), MOVE_AVOID_ENEMY_WEIGHT_3 | MOVE_ALLOW_ADJACENT_COASTAL, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		CvPlot* pLoopPlot = itr.plot();
#else
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif
		if (pLoopPlot->isCoastalLand())
		{
			if (pLoopPlot->isOwned())
			{
				if (((bBarbarian || !pLoopPlot->isBarbarian())) || GET_PLAYER(getOwnerINLINE()).isMinorCiv())
				{
					if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
					{
						PROFILE("CvUnitAI::AI_assaultSeaTransport.PotentialPlot");

						int iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
						if (iTargetCities > 0)
						{
							bool bCanCargoAllUnload = true;
							int iVisibleEnemyDefenders = pLoopPlot->getNumVisibleEnemyDefenders(this);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      11/30/08                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
							if (iVisibleEnemyDefenders > 0 || pLoopPlot->isCity())
							{
								for (uint i = 0; i < aGroupCargo.size(); ++i)
								{
									CvUnit* pAttacker = aGroupCargo[i];
									if( iVisibleEnemyDefenders > 0 )
									{
										CvUnit* pDefender = pLoopPlot->getBestDefender(NO_PLAYER, pAttacker->getOwnerINLINE(), pAttacker, true);
										if (pDefender == NULL || !pAttacker->canAttack(*pDefender))
										{
											bCanCargoAllUnload = false;
											break;
										}
									}
									else if( pLoopPlot->isCity() && !(pLoopPlot->isVisible(getTeam(),false)) )
									{
										// Assume city is defended, artillery can't naval invade
										if( pAttacker->combatLimit() < 100 )
										{
											bCanCargoAllUnload = false;
											break;
										}
									}
								}
							}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		

							if (bCanCargoAllUnload)
							{
								PROFILE("CvUnitAI::AI_assaultSeaTransport.CanUnload");

								int iPathTurns;
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/17/09                                jdog5000      */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
/* original bts code
								if (generatePath(pLoopPlot, 0, true, &iPathTurns))
*/
								//if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
								{
									//PROFILE("CvUnitAI::AI_assaultSeaTransport.ValidPath");

									int iValue = 1;

									if (!bIsAttackCity)
									{
										iValue += (AI_pillageValue(pLoopPlot, 15) * 10);
									}

									int iAssaultsHere = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ASSAULT, getGroup());

									iValue += (iAssaultsHere * 100);

									CvCity* pCity = pLoopPlot->getPlotCity();

									if (pCity == NULL)
									{
										for (int iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
										{
											CvPlot* pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iJ));

											if (pAdjacentPlot != NULL)
											{
												pCity = pAdjacentPlot->getPlotCity();

												if (pCity != NULL)
												{
													if (pCity->getOwnerINLINE() == pLoopPlot->getOwnerINLINE())
													{
														break;
													}
													else
													{
														pCity = NULL;
													}
												}
											}
										}
									}

									if (pCity != NULL)
									{
										PROFILE("CvUnitAI::AI_assaultSeaTransport.EvalCity");

										FAssert(isPotentialEnemy(pCity->getTeam(), pLoopPlot));

										if (!(pLoopPlot->isRiverCrossing(directionXY(pLoopPlot, pCity->plot()))))
										{
											iValue += (50 * -(GC.getRIVER_ATTACK_MODIFIER()));
										}

										iValue += 15 * (pLoopPlot->defenseModifier(getTeam(), false));
										iValue += 1000;
										iValue += (GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pCity->plot()) * 200);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/26/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
										// Continue attacking in area we have already captured cities
										if( pCity->area()->getCitiesPerPlayer(getOwnerINLINE()) > 0 )
										{
											if( pCity->AI_playerCloseness(getOwnerINLINE()) > 5 ) 
											{
												iValue *= 3;
												iValue /= 2;
											}
										}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		
									}

									int iThisTurnValueIncrement = 0;

									if (pCity != NULL)
									{
										iThisTurnValueIncrement = GC.getGameINLINE().getSorenRandNum(50, "AI Assault");

										if (pCity->area()->getNumCities() > 1)
										{
											iThisTurnValueIncrement *= 2;
											iThisTurnValueIncrement += iValue;
										}
									}

									iValue *= 1000;
									iThisTurnValueIncrement *= 1000;

									if (iTargetCities <= iAssaultsHere)
									{
										iValue /= 2;
										iThisTurnValueIncrement /= 2;
									}

									if (iTargetCities == 1)
									{
										if (iCargo > 7)
										{
											iValue *= 3;
											iValue /= iCargo - 4;

											iThisTurnValueIncrement *= 3;
											iThisTurnValueIncrement /= iCargo - 4;
										}
									}

									if (pLoopPlot->isCity())
									{
										if (iVisibleEnemyDefenders * 3 > iCargo)
										{
											iValue /= 10;
											iThisTurnValueIncrement /= 10;
										}
										else
										{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      11/30/08                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/*
// original bts code
											iValue *= iCargo;
											iValue /= std::max(1, (iVisibleEnemyDefenders * 3));
*/
											// Assume non-visible city is properly defended
											int iDivisor = std::max(pLoopPlot->getPlotCity()->AI_neededDefenders(), (iVisibleEnemyDefenders * 3));

											iValue *= iCargo;
											iValue /= iDivisor;
											iThisTurnValueIncrement *= iCargo;
											iThisTurnValueIncrement /= iDivisor;
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		
										}
									}
									else
									{
										if (0 == iVisibleEnemyDefenders)
										{
											iValue *= 4;
											iValue /= 3;
											iThisTurnValueIncrement *= 4;
											iThisTurnValueIncrement /= 3;
										}
										else
										{
											iValue /= iVisibleEnemyDefenders;
											iThisTurnValueIncrement /= iVisibleEnemyDefenders;
										}
									}

// Koshling - removing this - it can cause osciallation between targets
#if 0
									// if more than 3 turns to get there, then put some randomness into our preference of distance
									// +/- 33%
									if (iPathTurns > 3)
									{
										int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");

										iPathTurns *= 66 + iPathAdjustment;
										iPathTurns /= 100;
									}
#endif
									if (iValue > 0 && generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns, iBestValue == 0 ? MAX_INT : (iValue+iThisTurnValueIncrement)/iBestValue))
									{
										PROFILE("CvUnitAI::AI_assaultSeaTransport.ValidPath");

										if ( iPathTurns <= 1 )
										{
											iValue += iThisTurnValueIncrement;
										}

										iValue /= (iPathTurns + 1);

										if (iValue > iBestValue)
										{
											CvPlot* endTurnPlot = getPathEndTurnPlot();

											if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 80) )
											{
												iBestValue = iValue;
												pBestPlot = endTurnPlot;
												pBestAssaultPlot = pLoopPlot;
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestAssaultPlot != NULL))
	{
		PROFILE("CvUnitAI::AI_assaultSeaTransport.ProcessTarget");

		FAssert(!(pBestPlot->isImpassable(getTeam())));

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/11/10                                jdog5000      */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
		// Cancel missions of all those coming to join departing transport
		CvSelectionGroup* pLoopGroup = NULL;
		int iLoop = 0;
		CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());

		for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
		{
			if( pLoopGroup != getGroup() )
			{
				if( pLoopGroup->AI_getMissionAIType() == MISSIONAI_GROUP && pLoopGroup->getHeadUnitAI() == AI_getUnitAIType() )
				{
					CvUnit* pMissionUnit = pLoopGroup->AI_getMissionAIUnit();

					if( pMissionUnit != NULL && pMissionUnit->getGroup() == getGroup() )
					{
						pLoopGroup->clearMissionQueue();
					}
				}
			}
		}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


		if ((pBestPlot == pBestAssaultPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1))
		{
			if (atPlot(pBestAssaultPlot))
			{
				getGroup()->unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
				return true;
			}
			else
			{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/01/09                                jdog5000      */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
/* original bts code
				getGroup()->pushMission(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
*/
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/01/09                                jdog5000      */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
/* original bts code
			getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
*/
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	return false;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/07/10                                jdog5000      */
/*                                                                                              */
/* Naval AI, Efficiency                                                                         */
/************************************************************************************************/
// Returns true if a mission was pushed...
bool CvUnitAI::AI_assaultSeaReinforce(bool bBarbarian)
{
	PROFILE_FUNC();

	bool bIsAttackCity = (getUnitAICargo(UNITAI_ATTACK_CITY) > 0);
	
	FAssert(getGroup()->hasCargo());

	if (!canCargoAllMove())
	{
		return false;
	}

	if( !(getGroup()->canAllMove()) )
	{
		return false;
	}

	std::vector<CvUnit*> aGroupCargo;
	CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
	while (pUnitNode != NULL)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = plot()->nextUnitNode(pUnitNode);
		CvUnit* pTransport = pLoopUnit->getTransportUnit();
		if (pTransport != NULL && pTransport->getGroup() == getGroup())
		{
			aGroupCargo.push_back(pLoopUnit);
		}
	}

	int iCargo = getGroup()->getCargo();
	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestAssaultPlot = NULL;
	CvArea* pWaterArea = plot()->waterArea();
	bool bCity = plot()->isCity(true,getTeam());
	bool bCanMoveAllTerrain = getGroup()->canMoveAllTerrain();

	int iTargetCities;
	int iOurFightersHere;
	int iPathTurns;
	int iValue;

	// Loop over nearby plots for groups in enemy territory to reinforce
	{
		PROFILE("AI_assaultSeaReinforce.Nearby");

		int iRange = 2*baseMoves();
		int iDX, iDY;
		for (iDX = -(iRange); iDX <= iRange; iDX++)
		{
			for (iDY = -(iRange); iDY <= iRange; iDY++)
			{
				CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

				if( pLoopPlot != NULL )
				{
					if (pLoopPlot->isOwned())
					{
						if (isEnemy(pLoopPlot->getTeam(), pLoopPlot))
						{
							if ( bCanMoveAllTerrain || (pWaterArea != NULL && pLoopPlot->isAdjacentToArea(pWaterArea)) )
							{
								iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
								
								if (iTargetCities > 0)
								{
									iOurFightersHere = pLoopPlot->getNumDefenders(getOwnerINLINE());

									if( iOurFightersHere > 2 )
									{
										iPathTurns;
										if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
										{
											if( iPathTurns <= 2 )
											{
												CvPlot* pEndTurnPlot = getPathEndTurnPlot();

												iValue = 10*iTargetCities;
												iValue += 8*iOurFightersHere;
												iValue += 3*GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);

												iValue *= 100;

												iValue /= (iPathTurns + 1);

												if (iValue > iBestValue)
												{
													iBestValue = iValue;
													pBestPlot = pEndTurnPlot;
													pBestAssaultPlot = pLoopPlot;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
	{
		// Loop over other transport groups, looking for synchronized landing
		{
			PROFILE("AI_assaultSeaReinforce.Sync");

			int iLoop;
			for(CvSelectionGroup* pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).firstSelectionGroup(&iLoop); pLoopSelectionGroup; pLoopSelectionGroup = GET_PLAYER(getOwnerINLINE()).nextSelectionGroup(&iLoop))
			{
				if (pLoopSelectionGroup != getGroup())
				{				
					if (pLoopSelectionGroup->AI_getMissionAIType() == MISSIONAI_ASSAULT)
					{
						CvPlot* pLoopPlot = pLoopSelectionGroup->AI_getMissionAIPlot();

						if( pLoopPlot != NULL )
						{
							if (pLoopPlot->isOwned())
							{
								if (isPotentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
								{
									if ( bCanMoveAllTerrain || (pWaterArea != NULL && pLoopPlot->isAdjacentToArea(pWaterArea)) )
									{
										iTargetCities = pLoopPlot->area()->getCitiesPerPlayer(pLoopPlot->getOwnerINLINE());
										if (iTargetCities > 0)
										{
											int iAssaultsHere = pLoopSelectionGroup->getCargo();
											
											if ( iAssaultsHere > 2 )
											{
												//	Use approximate path lengths here as switching path calculations between stacks
												//	throws out all cached pathing data and is very expensive performance-wise
												int	iStepPathTurns = (10*GC.getMapINLINE().calculatePathDistance(plot(), pLoopPlot) + 5)/(10*baseMoves());
												int	iOtherStepPathTurns = (10*GC.getMapINLINE().calculatePathDistance(pLoopSelectionGroup->plot(), pLoopPlot) + 5)/(10*pLoopSelectionGroup->getHeadUnit()->baseMoves());

												if( (iStepPathTurns > iOtherStepPathTurns) && (iStepPathTurns < iOtherStepPathTurns + 6) )
												{
													iPathTurns;
													if (generatePath(pLoopPlot, MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
													{
														iValue = (iAssaultsHere * 5);
														iValue += iTargetCities*10;
 
														iValue *= 100;

														// if more than 3 turns to get there, then put some randomness into our preference of distance
														// +/- 33%
														if (iPathTurns > 3)
														{
															int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");

															iPathTurns *= 66 + iPathAdjustment;
															iPathTurns /= 100;
														}

														iValue /= (iPathTurns + 1);

														if (iValue > iBestValue)
														{
															iBestValue = iValue;
															pBestPlot = getPathEndTurnPlot();
															pBestAssaultPlot = pLoopPlot;
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	// Reinforce our cities in need
	if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
	{
		{
			PROFILE("AI_assaultSeaReinforce.Cities");
			int iLoop;
			CvCity* pLoopCity;

			for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
			{
				if( bCanMoveAllTerrain || (pWaterArea != NULL && (pLoopCity->waterArea(true) == pWaterArea || pLoopCity->secondWaterArea() == pWaterArea)) )
				{
					iValue = 0;
					if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE)
					{
						iValue = 3;
					}
					else if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE)
					{
						iValue = 2;
					}
					else if(pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_MASSING)
					{
						iValue = 1;
					}
					else if( bBarbarian && (pLoopCity->area()->getCitiesPerPlayer(BARBARIAN_PLAYER) > 0) )
					{
						iValue = 1;
					}

					if( iValue > 0 )
					{
						bool bCityDanger = pLoopCity->AI_isDanger();
						if( (bCity && pLoopCity->area() != area()) || bCityDanger || ((GC.getGameINLINE().getGameTurn() - pLoopCity->getGameTurnAcquired()) < 10 && pLoopCity->getPreviousOwner() != NO_PLAYER) )
						{
							int iOurPower = std::max(1, pLoopCity->area()->getPower(getOwnerINLINE()));
							// Enemy power includes barb power
							int iEnemyPower = GET_TEAM(getTeam()).countEnemyPowerByArea(pLoopCity->area());

							// Don't send troops to areas we are dominating already
							// Don't require presence of enemy cities, just a dangerous force
							if( iOurPower < (3*iEnemyPower) )
							{
								iPathTurns;
								if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
								{
									iValue *= 10*pLoopCity->AI_cityThreat();
							
									iValue += 20 * GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT, getGroup());
									
									iValue *= std::min(iEnemyPower, 3*iOurPower);
									iValue /= iOurPower;

									iValue *= 100;

									// if more than 3 turns to get there, then put some randomness into our preference of distance
									// +/- 33%
									if (iPathTurns > 3)
									{
										int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");

										iPathTurns *= 66 + iPathAdjustment;
										iPathTurns /= 100;
									}

									iValue /= (iPathTurns + 6);

									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = (bCityDanger ? getPathEndTurnPlot() : pLoopCity->plot());
										pBestAssaultPlot = pLoopCity->plot();
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot == NULL) && (pBestAssaultPlot == NULL))
	{
		if( bCity ) 
		{
			if( GET_TEAM(getTeam()).isAVassal() )
			{
				PROFILE("AI_assaultSeaReinforce.Vassal");

				TeamTypes eMasterTeam = NO_TEAM;

				for( int iI = 0; iI < MAX_CIV_TEAMS; iI++ )
				{
					if( GET_TEAM(getTeam()).isVassal((TeamTypes)iI) )
					{
						eMasterTeam = (TeamTypes)iI;
					}
				}

				if( (eMasterTeam != NO_TEAM) && GET_TEAM(getTeam()).isOpenBorders(eMasterTeam) )
				{
					for( int iI = 0; iI < MAX_CIV_PLAYERS; iI++ )
					{
						if( GET_PLAYER((PlayerTypes)iI).getTeam() == eMasterTeam )
						{
							int iLoop;
							CvCity* pLoopCity;

							for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
							{
								if( pLoopCity->area() != area() )
								{
									iValue = 0;
									if(pLoopCity->area()->getAreaAIType(eMasterTeam) == AREAAI_OFFENSIVE)
									{
										iValue = 2;
									}
									else if(pLoopCity->area()->getAreaAIType(eMasterTeam) == AREAAI_MASSING)
									{
										iValue = 1;
									}

									if( iValue > 0 )
									{
										if( bCanMoveAllTerrain || (pWaterArea != NULL && (pLoopCity->waterArea(true) == pWaterArea || pLoopCity->secondWaterArea() == pWaterArea)) )
										{
											int iOurPower = std::max(1, pLoopCity->area()->getPower(getOwnerINLINE()));
											iOurPower += GET_TEAM(eMasterTeam).countPowerByArea(pLoopCity->area());
											// Enemy power includes barb power
											int iEnemyPower = GET_TEAM(eMasterTeam).countEnemyPowerByArea(pLoopCity->area());

											// Don't send troops to areas we are dominating already
											// Don't require presence of enemy cities, just a dangerous force
											if( iOurPower < (2*iEnemyPower) )
											{
												int iPathTurns;
												if (generatePath(pLoopCity->plot(), MOVE_AVOID_ENEMY_WEIGHT_3, true, &iPathTurns))
												{
													iValue *= pLoopCity->AI_cityThreat();
											
													iValue += 10 * GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT, getGroup());
												
													iValue *= std::min(iEnemyPower, 3*iOurPower);
													iValue /= iOurPower;

													iValue *= 100;

													// if more than 3 turns to get there, then put some randomness into our preference of distance
													// +/- 33%
													if (iPathTurns > 3)
													{
														int iPathAdjustment = GC.getGameINLINE().getSorenRandNum(67, "AI Assault Target");

														iPathTurns *= 66 + iPathAdjustment;
														iPathTurns /= 100;
													}

													iValue /= (iPathTurns + 1);

													if (iValue > iBestValue)
													{
														CvPlot* endTurnPlot = getPathEndTurnPlot();

														if ( endTurnPlot == pLoopCity->plot() || !exposedToDanger(endTurnPlot, 60) )
														{
															iBestValue = iValue;
															pBestPlot = endTurnPlot;
															pBestAssaultPlot = pLoopCity->plot();
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestAssaultPlot != NULL))
	{
		FAssert(!(pBestPlot->isImpassable(getTeam())));

		// Cancel missions of all those coming to join departing transport
		CvSelectionGroup* pLoopGroup = NULL;
		int iLoop = 0;
		CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());

		for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
		{
			if( pLoopGroup != getGroup() )
			{
				if( pLoopGroup->AI_getMissionAIType() == MISSIONAI_GROUP && pLoopGroup->getHeadUnitAI() == AI_getUnitAIType() )
				{
					CvUnit* pMissionUnit = pLoopGroup->AI_getMissionAIUnit();

					if( pMissionUnit != NULL && pMissionUnit->getGroup() == getGroup() )
					{
						pLoopGroup->clearMissionQueue();
					}
				}
			}
		}

		if ((pBestPlot == pBestAssaultPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE()) == 1))
		{
			if (atPlot(pBestAssaultPlot))
			{
				getGroup()->unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
				return true;
			}
			else
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestAssaultPlot->getX_INLINE(), pBestAssaultPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_ASSAULT, pBestAssaultPlot);
		}
	}

	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/



// Returns true if a mission was pushed...
bool CvUnitAI::AI_settlerSeaTransport()
{
	PROFILE_FUNC();

	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
	CvPlot* pPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestFoundPlot;
	CvArea* pWaterArea;
	bool bValid;
	int iValue;
	int iBestValue;
	int iI;

	FAssert(getCargo() > 0);
	FAssert(getUnitAICargo(UNITAI_SETTLE) > 0);

	if (!canCargoAllMove())
	{
		return false;
	}

	//New logic should allow some new tricks like 
	//unloading settlers when a better site opens up locally
	//and delivering settlers
	//to inland sites

	pWaterArea = plot()->waterArea();
	FAssertMsg(pWaterArea != NULL, "Ship out of water?");

	CvUnit* pSettlerUnit = NULL;
	pPlot = plot();
	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (pLoopUnit->AI_getUnitAIType() == UNITAI_SETTLE)
			{
				pSettlerUnit = pLoopUnit;
				break;
			}
		}
	}
	
	FAssert(pSettlerUnit != NULL);
	
	int iAreaBestFoundValue = 0;
	CvPlot* pAreaBestPlot = NULL;

	int iOtherAreaBestFoundValue = 0;
	CvPlot* pOtherAreaBestPlot = NULL;

	for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
	{
		CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
		if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup()) == 0)
		{
			iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/13/09                                jdog5000      */
/*                                                                                              */
/* Settler AI                                                                                   */
/************************************************************************************************/
/* original bts code
			if (pCitySitePlot->getArea() == getArea())
			{
				if (iValue > iAreaBestFoundValue)
				{
*/
			// Only count city sites we can get to
			if (pCitySitePlot->getArea() == getArea() && pSettlerUnit->generatePath(pCitySitePlot, MOVE_SAFE_TERRITORY, true))
			{
				if (iValue > iAreaBestFoundValue)
				{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
					iAreaBestFoundValue = iValue;
					pAreaBestPlot = pCitySitePlot;
				}
			}
			else
			{
				if (iValue > iOtherAreaBestFoundValue)
				{
					iOtherAreaBestFoundValue = iValue;
					pOtherAreaBestPlot = pCitySitePlot;
				}
			}
		}
	}
	if ((0 == iAreaBestFoundValue) && (0 == iOtherAreaBestFoundValue))
	{
		return false;
	}
	
	if (iAreaBestFoundValue > iOtherAreaBestFoundValue)
	{
		//let the settler walk.
		getGroup()->unloadAll();
		getGroup()->pushMission(MISSION_SKIP);
		return true;
	}
	
	iBestValue = 0;
	pBestPlot = NULL;
	pBestFoundPlot = NULL;

	for (iI = 0; iI < GET_PLAYER(getOwnerINLINE()).AI_getNumCitySites(); iI++)
	{
		CvPlot* pCitySitePlot = GET_PLAYER(getOwnerINLINE()).AI_getCitySite(iI);
		if (!(pCitySitePlot->isVisibleEnemyUnit(this)))
		{
			if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCitySitePlot, MISSIONAI_FOUND, getGroup(), 4) == 0)
			{
				int iPathTurns;
				// BBAI TODO: Nearby plots too if much shorter (settler walk from there)
				// also, if plots are in area player already has cities, then may not be coastal ... (see Earth 1000 AD map for Inca)
				if (generatePath(pCitySitePlot, 0, true, &iPathTurns))
				{
					iValue = pCitySitePlot->getFoundValue(getOwnerINLINE());
					iValue *= 1000;
					iValue /= (2 + iPathTurns);
					
					if (iValue > iBestValue)
					{
						CvPlot* endTurnPlot = getPathEndTurnPlot();

						if ( endTurnPlot == pCitySitePlot || !exposedToDanger(endTurnPlot, 80) )
						{
							iBestValue = iValue;
							pBestPlot = endTurnPlot;
							pBestFoundPlot = pCitySitePlot;
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
	{
/************************************************************************************************/
/* Afforess	Mountains Start		 09/18/09                                           		 */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		FAssert(!(pBestPlot->isImpassable(getTeam()))); // added getTeam()
/************************************************************************************************/
/* Afforess	Mountains End       END        		                                             */
/************************************************************************************************/


		if ((pBestPlot == pBestFoundPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE()) == 1))
		{
			if (atPlot(pBestFoundPlot))
			{
				unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
				return true;
			}
			else
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
		}
	}

	//Try original logic
	//(sometimes new logic breaks)
	pPlot = plot();

	iBestValue = 0;
	pBestPlot = NULL;
	pBestFoundPlot = NULL;
	
	int iMinFoundValue = GET_PLAYER(getOwnerINLINE()).AI_getMinFoundValue();

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (pLoopPlot->isCoastalLand())
		{
			iValue = pLoopPlot->getFoundValue(getOwnerINLINE());

			if ((iValue > iBestValue) && (iValue >= iMinFoundValue))
			{
				bValid = false;

				pUnitNode = pPlot->headUnitNode();

				while (pUnitNode != NULL)
				{
					pLoopUnit = ::getUnit(pUnitNode->m_data);
					pUnitNode = pPlot->nextUnitNode(pUnitNode);

					if (pLoopUnit->getTransportUnit() == this)
					{
						if (pLoopUnit->canFound(pLoopPlot))
						{
							bValid = true;
							break;
						}
					}
				}

				if (bValid)
				{
					if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_FOUND, getGroup(), 4) == 0)
						{
							if (generatePath(pLoopPlot, 0, true))
							{
								iBestValue = iValue;
								pBestPlot = getPathEndTurnPlot();
								pBestFoundPlot = pLoopPlot;
							}
						}
					}
				}
			}
		}
	}
	
	if ((pBestPlot != NULL) && (pBestFoundPlot != NULL))
	{
/************************************************************************************************/
/* Afforess	Mountains Start		 09/18/09                                           		 */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		FAssert(!(pBestPlot->isImpassable(getTeam()))); // added getTeam()
/************************************************************************************************/
/* Afforess	Mountains End       END        		                                             */
/************************************************************************************************/


		if ((pBestPlot == pBestFoundPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE()) == 1))
		{
			if (atPlot(pBestFoundPlot))
			{
				unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
				return true;
			}
			else
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestFoundPlot->getX_INLINE(), pBestFoundPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestFoundPlot);
		}
	}
	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_settlerSeaFerry()
{
	PROFILE_FUNC();

	FAssert(getCargo() > 0);
	FAssert(getUnitAICargo(UNITAI_WORKER) > 0);

	if (!canCargoAllMove())
	{
		return false;
	}

	CvArea* pWaterArea = plot()->waterArea();
	FAssertMsg(pWaterArea != NULL, "Ship out of water?");

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	
	CvCity* pLoopCity;
	int iLoop;
	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		int iValue = pLoopCity->AI_getWorkersNeeded();
		if (iValue > 0)
		{
			iValue -= GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_FOUND, getGroup());
			if (iValue > 0)
			{
				int iPathTurns;
				if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
				{
					iValue += std::max(0, (GET_PLAYER(getOwnerINLINE()).AI_neededWorkers(pLoopCity->area()) - GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_WORKER)));
					iValue *= 1000;
					iValue /= 4 + iPathTurns;
					if (atPlot(pLoopCity->plot()))
					{
						iValue += 100;
					}
					else
					{
						iValue += GC.getGame().getSorenRandNum(100, "AI settler sea ferry");
					}
					if (iValue > iBestValue)
					{
						CvPlot* endTurnPlot = getPathEndTurnPlot();

						if ( endTurnPlot == pLoopCity->plot() || !exposedToDanger(endTurnPlot, 80) )
						{
							iBestValue = iValue;
							pBestPlot = endTurnPlot;	
						}
					}
				}
			}
		}
	}
	
	if (pBestPlot != NULL)
	{
		if (atPlot(pBestPlot))
		{
			unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
			return true;
		}
		else
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_FOUND, pBestPlot);
		}
	}
	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_specialSeaTransportMissionary()
{
	PROFILE_FUNC();

	CLLNode<IDInfo>* pUnitNode;
	CvCity* pCity;
	CvUnit* pMissionaryUnit;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
	CvPlot* pPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestSpreadPlot;
	int iPathTurns;
	int iValue;
	int iCorpValue;
	int iBestValue;
	int iJ;
	bool bExecutive = false;

	FAssert(getCargo() > 0);
	FAssert(getUnitAICargo(UNITAI_MISSIONARY) > 0);

	if (!canCargoAllMove())
	{
		return false;
	}

	pPlot = plot();

	pMissionaryUnit = NULL;

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (pLoopUnit->AI_getUnitAIType() == UNITAI_MISSIONARY)
			{
				pMissionaryUnit = pLoopUnit;
				break;
			}
		}
	}

	if (pMissionaryUnit == NULL)
	{
		return false;
	}

	iBestValue = 0;
	pBestPlot = NULL;
	pBestSpreadPlot = NULL;

	// XXX what about non-coastal cities?
#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), MOVE_ALLOW_ADJACENT_COASTAL, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	int iI;
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		if (pLoopPlot->isCoastalLand())
		{
			pCity = pLoopPlot->getPlotCity();

			if (pCity != NULL)
			{
				iValue = 0;
				iCorpValue = 0;

				for (iJ = 0; iJ < GC.getNumReligionInfos(); iJ++)
				{
					if (pMissionaryUnit->canSpread(pLoopPlot, ((ReligionTypes)iJ)))
					{
						if (GET_PLAYER(getOwnerINLINE()).getStateReligion() == ((ReligionTypes)iJ))
						{
							iValue += 3;
						}

						if (GET_PLAYER(getOwnerINLINE()).hasHolyCity((ReligionTypes)iJ))
						{
							iValue++;
						}
					}
				}

				for (iJ = 0; iJ < GC.getNumCorporationInfos(); iJ++)
				{
					if (pMissionaryUnit->canSpreadCorporation(pLoopPlot, ((CorporationTypes)iJ)))
					{
						if (GET_PLAYER(getOwnerINLINE()).hasHeadquarters((CorporationTypes)iJ))
						{
							iCorpValue += 3;
						}
					}
				}

				if (iValue > 0)
				{
					if (!(pLoopPlot->isVisibleEnemyUnit(this)))
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_SPREAD, getGroup()) == 0)
						{
							if (generatePath(pLoopPlot, 0, true, &iPathTurns))
							{
								iValue *= pCity->getPopulation();

								if (pCity->getOwnerINLINE() == getOwnerINLINE())
								{
									iValue *= 4;
								}
								else if (pCity->getTeam() == getTeam())
								{
									iValue *= 3;
								}

								if (pCity->getReligionCount() == 0)
								{
									iValue *= 2;
								}

								iValue /= (pCity->getReligionCount() + 1);

								if (iPathTurns == 1)
								{
									iValue *= 2;
								}

								iValue *= 1000;

								iValue /= (iPathTurns + 1);

								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = getPathEndTurnPlot();
									pBestSpreadPlot = pLoopPlot;
									bExecutive = false;
								}
							}
						}
					}
				}

				if (iCorpValue > 0)
				{
					if (!(pLoopPlot->isVisibleEnemyUnit(this)))
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_SPREAD_CORPORATION, getGroup()) == 0)
						{
							if (generatePath(pLoopPlot, 0, true, &iPathTurns))
							{
								iCorpValue *= pCity->getPopulation();

								FAssert(iPathTurns > 0);

								if (iPathTurns == 1)
								{
/************************************************************************************************/
/* UNOFFICIAL_PATCH                       02/22/10                                jdog5000      */
/*                                                                                              */
/* Bugfix                                                                                       */
/************************************************************************************************/
/* original bts code
									iValue *= 2;
*/
									iCorpValue *= 2;
/************************************************************************************************/
/* UNOFFICIAL_PATCH                        END                                                  */
/************************************************************************************************/
								}

								iCorpValue *= 1000;

								iCorpValue /= (iPathTurns + 1);

								if (iCorpValue > iBestValue)
								{
									iBestValue = iCorpValue;
									pBestPlot = getPathEndTurnPlot();
									pBestSpreadPlot = pLoopPlot;
									bExecutive = true;
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestSpreadPlot != NULL))
	{
/************************************************************************************************/
/* Afforess	Mountains Start		 09/18/09                                           		 */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		FAssert(!(pBestPlot->isImpassable(getTeam())) || canMoveImpassable()); // added getTeam()
/************************************************************************************************/
/* Afforess	Mountains End       END        		                                             */
/************************************************************************************************/
		if ((pBestPlot == pBestSpreadPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE()) == 1))
		{
			if (atPlot(pBestSpreadPlot))
			{
				unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
				return true;
			}
			else
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestSpreadPlot->getX_INLINE(), pBestSpreadPlot->getY_INLINE(), 0, false, false, bExecutive ? MISSIONAI_SPREAD_CORPORATION : MISSIONAI_SPREAD, pBestSpreadPlot);
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, bExecutive ? MISSIONAI_SPREAD_CORPORATION : MISSIONAI_SPREAD, pBestSpreadPlot);
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_specialSeaTransportSpy()
{
	//PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestSpyPlot;
	PlayerTypes eBestPlayer;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iI;

	FAssert(getCargo() > 0);
	FAssert(getUnitAICargo(UNITAI_SPY) > 0);

	if (!canCargoAllMove())
	{
		return false;
	}

	iBestValue = 0;
	eBestPlayer = NO_PLAYER;

	for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive())
		{
			if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
			{
				if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_ANNOYED)
				{
					iValue = GET_PLAYER((PlayerTypes)iI).getTotalPopulation();

					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						eBestPlayer = ((PlayerTypes)iI);
					}
				}
			}
		}
	}

	if (eBestPlayer == NO_PLAYER)
	{
		return false;
	}

	pBestPlot = NULL;
	pBestSpyPlot = NULL;

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), MOVE_ALLOW_ADJACENT_COASTAL, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	int iI;
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		if (pLoopPlot->isCoastalLand())
		{
			if (pLoopPlot->getOwnerINLINE() == eBestPlayer)
			{
				iValue = pLoopPlot->area()->getCitiesPerPlayer(eBestPlayer);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/23/10                                jdog5000      */
/*                                                                                              */
/* Efficiency                                                                                   */
/************************************************************************************************/
				iValue *= 1000;

				if (iValue > iBestValue)
				{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ATTACK_SPY, getGroup(), 4) == 0)
					{
						if (generatePath(pLoopPlot, 0, true, &iPathTurns))
						{
							iValue /= (iPathTurns + 1);

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = getPathEndTurnPlot();
								pBestSpyPlot = pLoopPlot;
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestSpyPlot != NULL))
	{
/************************************************************************************************/
/* Afforess	Mountains Start		 09/18/09                                           		 */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		FAssert(!(pBestPlot->isImpassable(getTeam()))); // added getTeam()
/************************************************************************************************/
/* Afforess	Mountains End       END        		                                             */
/************************************************************************************************/
		if ((pBestPlot == pBestSpyPlot) || (stepDistance(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), pBestSpyPlot->getX_INLINE(), pBestSpyPlot->getY_INLINE()) == 1))
		{
			if (atPlot(pBestSpyPlot))
			{
				unloadAll(); // XXX is this dangerous (not pushing a mission...) XXX air units?
				return true;
			}
			else
			{
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestSpyPlot->getX_INLINE(), pBestSpyPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSpyPlot);
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY, pBestSpyPlot);
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_carrierSeaTransport()
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pLoopPlotAir;
	CvPlot* pBestPlot;
	CvPlot* pBestCarrierPlot;
	int iMaxAirRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iMaxAirRange = 0;

	std::vector<CvUnit*> aCargoUnits;
	getCargoUnits(aCargoUnits);
	for (uint i = 0; i < aCargoUnits.size(); ++i)
	{
		iMaxAirRange = std::max(iMaxAirRange, aCargoUnits[i]->airRange());
	}

	if (iMaxAirRange == 0)
	{
		return false;
	}

	iBestValue = 0;
	pBestPlot = NULL;
	pBestCarrierPlot = NULL;

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/22/10                                jdog5000      */
/*                                                                                              */
/* Naval AI, War tactics, Efficiency                                                            */
/************************************************************************************************/
#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	int iI;
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		//if (AI_plotValid(pLoopPlot))
		{
			if (pLoopPlot->isWater() && pLoopPlot->isAdjacentToLand())
			{
				if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
				{
					iValue = 0;

					for (iDX = -(iMaxAirRange); iDX <= iMaxAirRange; iDX++)
					{
						for (iDY = -(iMaxAirRange); iDY <= iMaxAirRange; iDY++)
						{
							pLoopPlotAir = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iDX, iDY);

							if (pLoopPlotAir != NULL)
							{
								if (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pLoopPlotAir->getX_INLINE(), pLoopPlotAir->getY_INLINE()) <= iMaxAirRange)
								{
									if (!(pLoopPlotAir->isBarbarian()))
									{
										if (potentialWarAction(pLoopPlotAir))
										{
											if (pLoopPlotAir->isCity())
											{
												iValue += 3;

												// BBAI: Support invasions
												iValue += (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlotAir, MISSIONAI_ASSAULT, getGroup(), 2) * 6);
											}

											if (pLoopPlotAir->getImprovementType() != NO_IMPROVEMENT)
											{
												iValue += 2;
											}

											if (plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pLoopPlotAir->getX_INLINE(), pLoopPlotAir->getY_INLINE()) <= iMaxAirRange/2)
											{
												// BBAI: Support/air defense for land troops
												iValue += pLoopPlotAir->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE());
											}
										}
									}
								}
							}
						}
					}

					if( iValue > 0 )
					{
						iValue *= 1000;

						for (int iDirection = 0; iDirection < NUM_DIRECTION_TYPES; iDirection++)
						{
							CvPlot* pDirectionPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), (DirectionTypes)iDirection);
							if (pDirectionPlot != NULL)
							{
								if (pDirectionPlot->isCity() && isEnemy(pDirectionPlot->getTeam(), pLoopPlot))
								{
									iValue /= 2;
									break;
								}
							}
						}

						if (iValue > iBestValue)
						{
							bool bStealth = (getInvisibleType() != NO_INVISIBLE);
							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_CARRIER, getGroup(), bStealth ? 5 : 3) <= (bStealth ? 0 : 3))
							{
								if (generatePath(pLoopPlot, 0, true, &iPathTurns))
								{
									iValue /= (iPathTurns + 1);

									if (iValue > iBestValue)
									{
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 70) )
										{
											iBestValue = iValue;
											pBestPlot = endTurnPlot;
											pBestCarrierPlot = pLoopPlot;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if ((pBestPlot != NULL) && (pBestCarrierPlot != NULL))
	{
		if (atPlot(pBestCarrierPlot))
		{
			if (getGroup()->hasCargo())
			{
				CvPlot* pPlot = plot();

				int iNumUnits = pPlot->getNumUnits();

				for (int i = 0; i < iNumUnits; ++i)
				{
					bool bDone = true;
					CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
					while (pUnitNode != NULL)
					{
						CvUnit* pCargoUnit = ::getUnit(pUnitNode->m_data);
						pUnitNode = pPlot->nextUnitNode(pUnitNode);
					
						if (pCargoUnit->isCargo())
						{
							FAssert(pCargoUnit->getTransportUnit() != NULL);
							if (pCargoUnit->getOwnerINLINE() == getOwnerINLINE() && (pCargoUnit->getTransportUnit()->getGroup() == getGroup()) && (pCargoUnit->getDomainType() == DOMAIN_AIR))
							{
								if (pCargoUnit->canMove() && pCargoUnit->isGroupHead())
								{
									// careful, this might kill the cargo group
									if (pCargoUnit->getGroup()->AI_update())
									{
										bDone = false;
										break;
									}
								}
							}
						}
					}

					if (bDone)
					{
						break;
					}
				}
			}

			if (canPlunder(pBestCarrierPlot))
			{
				getGroup()->pushMission(MISSION_PLUNDER, -1, -1, 0, false, false, MISSIONAI_CARRIER, pBestCarrierPlot);
			}
			else
			{
				getGroup()->pushMission(MISSION_SKIP);
			}
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_CARRIER, pBestCarrierPlot);
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_connectPlot(CvPlot* pPlot, int iRange)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	int iLoop;
	int iBasePathFlags = MOVE_SAFE_TERRITORY | MOVE_AVOID_ENEMY_UNITS | (isHuman() ? MOVE_OUR_TERRITORY : MOVE_IGNORE_DANGER | MOVE_RECONSIDER_ON_LEAVING_OWNED);

	FAssert(canBuildRoute());

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
	// BBAI efficiency: check area for land units before generating paths
	if( (getDomainType() == DOMAIN_LAND) && (pPlot->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
	{
		return false;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if (!pPlot->isVisible(getTeam(),false) || !pPlot->isVisibleEnemyUnit(this))
	{
		if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_BUILD, getGroup(), iRange) == 0)
		{
			if (generatePath(pPlot, iBasePathFlags, true))
			{
				bool	bHasPossibleTargetCity = false;

				for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
				{
					if (!(pPlot->isConnectedTo(pLoopCity)))
					{
						bHasPossibleTargetCity |= !pLoopCity->plot()->isVisibleEnemyUnit(this);

						FAssertMsg(pPlot->getPlotCity() != pLoopCity, "pPlot->getPlotCity() is not expected to be equal with pLoopCity");

						if (plot()->getPlotGroup(getOwnerINLINE()) == pLoopCity->plot()->getPlotGroup(getOwnerINLINE()))
						{
							PROFILE("CvUnitAI::AI_connectPlot.StrangeCase");

							if ( !isHuman() &&
								 (AI_workerNeedsToAwaitDefender(pPlot) ||
								  AI_workerNeedsToAwaitDefender(getPathEndTurnPlot())))
							{
								return true;
							}

							return getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_SAFE_TERRITORY | MOVE_WITH_CAUTION, false, false, MISSIONAI_BUILD, pPlot);
						}
					}
				}

				CvReachablePlotSet	plotSet(getGroup(), iBasePathFlags);
				if ( bHasPossibleTargetCity )
				{
					plotSet.Populate(MAX_INT);
				}
				else
				{
					return false;
				}

				for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
				{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
					// BBAI efficiency: check same area
					//if( (pLoopCity->area() != pPlot->area()) )
					if( plotSet.find(pLoopCity->plot()) == plotSet.end() )
					{
						continue;
					}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

					if (!(pPlot->isConnectedTo(pLoopCity)))
					{
						FAssertMsg(pPlot->getPlotCity() != pLoopCity, "pPlot->getPlotCity() is not expected to be equal with pLoopCity");

						if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
						{
							if (generatePath(pLoopCity->plot(), iBasePathFlags, true))
							{
								if (atPlot(pPlot)) // need to test before moving...
								{
									return getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY | MOVE_WITH_CAUTION, false, false, MISSIONAI_BUILD, pPlot);
								}
								else
								{
									if ( !isHuman() &&
										 (AI_workerNeedsToAwaitDefender(pLoopCity->plot()) ||
										  AI_workerNeedsToAwaitDefender(getPathEndTurnPlot())))
									{
										return true;
									}

									if ( getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY | MOVE_WITH_CAUTION, false, false, MISSIONAI_BUILD, pPlot) )
									{
										getGroup()->pushMission(MISSION_ROUTE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), MOVE_SAFE_TERRITORY | MOVE_WITH_CAUTION, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pPlot);

										return true;
									}
								}

								return false;
							}
						}
					}
				}
			}
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_improveCity(CvCity* pCity)
{
	PROFILE_FUNC();

	CvPlot* pBestPlot;
	BuildTypes eBestBuild;
	MissionTypes eMission;

	if (AI_bestCityBuild(pCity, &pBestPlot, &eBestBuild, NULL, this))
	{
		FAssertMsg(pBestPlot != NULL, "BestPlot is not assigned a valid value");
		FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
		FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
		if ((plot()->getWorkingCity() != pCity) || (GC.getBuildInfo(eBestBuild).getRoute() != NO_ROUTE))
		{
			eMission = MISSION_ROUTE_TO;
		}
		else
		{
			int iPathTurns;

			eMission = MISSION_MOVE_TO;
			if (NULL != pBestPlot && generatePath(pBestPlot, MOVE_WITH_CAUTION, false, &iPathTurns) && (iPathTurns == 1) && (getPathMovementRemaining() == 0))
			{
				if (pBestPlot->getRouteType() != NO_ROUTE)
				{
					eMission = MISSION_ROUTE_TO;
				}
			}
			else if (plot()->getRouteType() == NO_ROUTE)
			{
				int iPlotMoveCost = 0;
				iPlotMoveCost = ((plot()->getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(plot()->getTerrainType()).getMovementCost() : GC.getFeatureInfo(plot()->getFeatureType()).getMovementCost());

				if (plot()->isHills())
				{
					iPlotMoveCost += GC.getHILLS_EXTRA_MOVEMENT();
				}
/************************************************************************************************/
/* Afforess	Mountains Start		 07/29/09                                           		 */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
				if (plot()->isPeak())
				{
					iPlotMoveCost += GC.getPEAK_EXTRA_MOVEMENT();
				}
/************************************************************************************************/
/* Afforess	Mountains End       END    		                                                 */
/************************************************************************************************/
				if (iPlotMoveCost > 1)
				{
					eMission = MISSION_ROUTE_TO;
				}
			}
		}
		
		//	In this routine the last path generated isn't necessarily the one for the best
		//	plot, so to get the end path turn plot regenerate it now
		if ( !isHuman() &&
			 (AI_workerNeedsToAwaitDefender(pBestPlot) ||
			  (!atPlot(pBestPlot) && generatePath(pBestPlot, MOVE_WITH_CAUTION) && AI_workerNeedsToAwaitDefender(getPathEndTurnPlot()))))
		{
			if ( !atPlot(pBestPlot) )
			{
				//	If we're already they might as well get on with it while we wait for an escort
				return true;
			}
		}

		eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);

		if (getGroup()->pushMissionInternal(eMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), isHuman() ? 0 : MOVE_WITH_CAUTION, false, false, MISSIONAI_BUILD, pBestPlot))
		{
			getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);

			return true;
		}
	}

	return false;
}

bool CvUnitAI::AI_improveLocalPlot(int iRange, CvCity* pIgnoreCity)
{
	
	int iX, iY;
	
	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestEndTurnPlot = NULL;
	BuildTypes eBestBuild = NO_BUILD;
	
	for (iX = -iRange; iX <= iRange; iX++)
	{
		for (iY = -iRange; iY <= iRange; iY++)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
			if ((pLoopPlot != NULL) && (pLoopPlot->isCityRadius()))
			{
				CvCity* pCity = pLoopPlot->getWorkingCity();
				if ((NULL != pCity) && (pCity->getOwnerINLINE() == getOwnerINLINE()))
				{
					if ((NULL == pIgnoreCity) || (pCity != pIgnoreCity))
					{
						if (AI_plotValid(pLoopPlot))
						{
							int iIndex = pCity->getCityPlotIndex(pLoopPlot);
							if (iIndex != CITY_HOME_PLOT)
							{
								if (((NULL == pIgnoreCity) || ((pCity->AI_getWorkersNeeded() > 0) && (pCity->AI_getWorkersHave() < (1 + pCity->AI_getWorkersNeeded() * 2 / 3)))) && (pCity->AI_getBestBuild(iIndex) != NO_BUILD))
								{
									if (canBuild(pLoopPlot, pCity->AI_getBestBuild(iIndex)))
									{
										bool bAllowed = true;

										if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION))
										{
											if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && pLoopPlot->getImprovementType() != GC.getDefineINT("RUINS_IMPROVEMENT"))
											{
											/************************************************************************************************/
												/* Afforess	                  Start		 01/19/10                                               */
												/*                                                                                              */
												/*   Automated Workers Can still replace Depleted Mines                                         */
											/************************************************************************************************/
												if (!GC.getImprovementInfo((ImprovementTypes)pLoopPlot->getImprovementType()).isDepletedMine())
												{
													bAllowed = false;
												}
											/************************************************************************************************/
												/* Afforess	                     END                                                            */
											/************************************************************************************************/
											}
										}

										if (bAllowed)
										{
											if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && GC.getBuildInfo(pCity->AI_getBestBuild(iIndex)).getImprovement() != NO_IMPROVEMENT)
											{
												bAllowed = false;
											}
										}

										if (bAllowed)
										{
											int iValue = pCity->AI_getBestBuildValue(iIndex);
											int iPathTurns;
											if (generatePath(pLoopPlot, isHuman() ? 0 : MOVE_IGNORE_DANGER, true, &iPathTurns))
											{
												int iMaxWorkers = 1;
												if (plot() == pLoopPlot)
												{
													iValue *= 3;
													iValue /= 2;
												}
												else if (getPathMovementRemaining() == 0)
												{
													iPathTurns++;
												}
												else if (iPathTurns <= 1)
												{
													iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, pCity->AI_getBestBuild(iIndex));											
												}

												if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
												{
													iValue *= 1000;
													iValue /= 1 + iPathTurns;

													if (iValue > iBestValue)
													{
														iBestValue = iValue;
														pBestPlot = pLoopPlot;
														pBestEndTurnPlot = getPathEndTurnPlot();
														eBestBuild = pCity->AI_getBestBuild(iIndex);											
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	
	if (pBestPlot != NULL)
	{
	    FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
	    FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");

		FAssert(pBestPlot->getWorkingCity() != NULL);

		MissionTypes eMission = MISSION_MOVE_TO;

		int iPathTurns;
		if (generatePath(pBestPlot, 0, true, &iPathTurns) && (iPathTurns == 1) && (getPathMovementRemaining() == 0))
		{
			if (pBestPlot->getRouteType() != NO_ROUTE)
			{
				eMission = MISSION_ROUTE_TO;
			}				
		}
		else if (plot()->getRouteType() == NO_ROUTE)
		{
			int iPlotMoveCost = 0;
			iPlotMoveCost = ((plot()->getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(plot()->getTerrainType()).getMovementCost() : GC.getFeatureInfo(plot()->getFeatureType()).getMovementCost());

			if (plot()->isHills())
			{
				iPlotMoveCost += GC.getHILLS_EXTRA_MOVEMENT();
			}
/************************************************************************************************/
/* Afforess	Mountains Start		 07/29/09                                           		 */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
			if (plot()->isPeak())
			{
				iPlotMoveCost += GC.getPEAK_EXTRA_MOVEMENT();
			}
/************************************************************************************************/
/* Afforess	Mountains End       END        		                                             */
/************************************************************************************************/
			if (iPlotMoveCost > 1)
			{
				eMission = MISSION_ROUTE_TO;
			}
		}
		
		eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);

		if ( !isHuman() &&
			 (AI_workerNeedsToAwaitDefender(pBestPlot) ||
			  AI_workerNeedsToAwaitDefender(pBestEndTurnPlot)))
		{
			return true;
		}

		CvPlot* pMissionPlot = getGroup()->AI_getMissionAIPlot();

		if (pMissionPlot != NULL && pMissionPlot->getWorkingCity() != NULL && getGroup()->AI_getMissionAIType() == MISSIONAI_BUILD )
		{
			OutputDebugString(CvString::format("Worker at (%d,%d) detaching from mission for city %S\n", plot()->getX_INLINE(), plot()->getY_INLINE(), pMissionPlot->getWorkingCity()->getName().GetCString()).c_str());
			pMissionPlot->getWorkingCity()->AI_changeWorkersHave(-1);
		}
		else if (plot()->getWorkingCity() != NULL)
		{
			OutputDebugString(CvString::format("Worker at (%d,%d) detaching from local city %S\n", plot()->getX_INLINE(), plot()->getY_INLINE(), plot()->getWorkingCity()->getName().GetCString()).c_str());
			plot()->getWorkingCity()->AI_changeWorkersHave(-1);
		}

		if (NULL != pBestPlot->getWorkingCity())
		{
			OutputDebugString(CvString::format("Worker at (%d,%d) attaching mission for city %S\n", plot()->getX_INLINE(), plot()->getY_INLINE(), pBestPlot->getWorkingCity()->getName().GetCString()).c_str());
			pBestPlot->getWorkingCity()->AI_changeWorkersHave(+1);
		}

		if (getGroup()->pushMissionInternal(eMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), (isHuman() ? 0 : MOVE_WITH_CAUTION), false, false, MISSIONAI_BUILD, pBestPlot))
		{
			getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
			return true;
		}
	}
	
	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_nextCityToImprove(CvCity* pCity)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pPlot;
	CvPlot* pBestPlot;
	CvPlot* pEndTurnPlot;
	BuildTypes eBuild;
	BuildTypes eBestBuild;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	int iBasePathFlags = MOVE_SAFE_TERRITORY | MOVE_AVOID_ENEMY_UNITS | (isHuman() ? MOVE_OUR_TERRITORY : MOVE_IGNORE_DANGER | MOVE_RECONSIDER_ON_LEAVING_OWNED);

	iBestValue = 0;
	eBestBuild = NO_BUILD;
	pBestPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (pLoopCity != pCity)
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/22/10                                jdog5000      */
/*                                                                                              */
/* Worker AI, Efficiency                                                                        */
/************************************************************************************************/
			// BBAI efficiency: check area for land units before path generation
			/*if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
			{
				continue;
			}*/

			//iValue = pLoopCity->AI_totalBestBuildValue(area());
			int iWorkersNeeded = pLoopCity->AI_getWorkersNeeded();
			int iWorkersHave = pLoopCity->AI_getWorkersHave();
			
			iValue = std::max(0, iWorkersNeeded - iWorkersHave) * 100;
			iValue += iWorkersNeeded * 10;
			iValue *= (iWorkersNeeded + 1);
			iValue /= (iWorkersHave + 1);

			if (iValue > 0)
			{
				if (AI_bestCityBuild(pLoopCity, &pPlot, &eBuild, NULL, this))
				{
					FAssert(pPlot != NULL);
					FAssert(eBuild != NO_BUILD);

					if( AI_plotValid(pPlot) )
					{
						iValue *= 1000;

						if (pLoopCity->isCapital())
						{
							iValue *= 2;
						}

						if( iValue > iBestValue )
						{
							PROFILE("CvUnitAI::AI_nextCityToImprove.Pathing");
							if( generatePath(pPlot, iBasePathFlags, true, &iPathTurns) )
							{
								PROFILE("CvUnitAI::AI_nextCityToImprove.Pathed");
								iValue /= (iPathTurns + 1);

								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									eBestBuild = eBuild;
									pBestPlot = pPlot;
									pEndTurnPlot = getPathEndTurnPlot();
									FAssert(!atPlot(pBestPlot) || NULL == pCity || pCity->AI_getWorkersNeeded() == 0 || pCity->AI_getWorkersHave() > pCity->AI_getWorkersNeeded() + 1);
								}
							}
						}
					}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
	    FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
	    FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");

		if ( !isHuman() &&
			 (AI_workerNeedsToAwaitDefender(pBestPlot) ||
			  AI_workerNeedsToAwaitDefender(pEndTurnPlot)))
		{
			return true;
		}

		CvPlot* pMissionPlot = getGroup()->AI_getMissionAIPlot();

		if (pMissionPlot != NULL && pMissionPlot->getWorkingCity() != NULL && getGroup()->AI_getMissionAIType() == MISSIONAI_BUILD )
		{
			OutputDebugString(CvString::format("Worker at (%d,%d) detaching from mission for city %S\n", plot()->getX_INLINE(), plot()->getY_INLINE(), pMissionPlot->getWorkingCity()->getName().GetCString()).c_str());
			pMissionPlot->getWorkingCity()->AI_changeWorkersHave(-1);
		}
		else if (plot()->getWorkingCity() != NULL)
		{
			OutputDebugString(CvString::format("Worker at (%d,%d) detaching from local city %S\n", plot()->getX_INLINE(), plot()->getY_INLINE(), plot()->getWorkingCity()->getName().GetCString()).c_str());
			plot()->getWorkingCity()->AI_changeWorkersHave(-1);
		}

		FAssert(pBestPlot->getWorkingCity() != NULL || GC.getBuildInfo(eBestBuild).getImprovement() == NO_IMPROVEMENT);
		if (NULL != pBestPlot->getWorkingCity())
		{
			OutputDebugString(CvString::format("Worker at (%d,%d) attaching mission for city %S\n", plot()->getX_INLINE(), plot()->getY_INLINE(), pBestPlot->getWorkingCity()->getName().GetCString()).c_str());
			pBestPlot->getWorkingCity()->AI_changeWorkersHave(+1);
		}
		
		eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);

		if (getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((isHuman() ? 0 : MOVE_WITH_CAUTION) | MOVE_SAFE_TERRITORY), false, false, MISSIONAI_BUILD, pBestPlot) )
		{
			getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);
			return true;
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_nextCityToImproveAirlift()
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iLoop;

	if (getGroup()->getNumUnits() > 1)
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getMaxAirlift() == 0)
	{
		return false;
	}

	iBestValue = 0;
	pBestPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (pLoopCity != pCity)
		{
			if (canAirliftAt(pCity->plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
			{
				iValue = pLoopCity->AI_totalBestBuildValue(pLoopCity->area());

				if (iValue > iBestValue)
				{
					iBestValue = iValue;
					pBestPlot = pLoopCity->plot();
					FAssert(pLoopCity != pCity);
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_AIRLIFT, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}

	return false;
}

bool CvUnitAI::AI_scrubFallout()
{
	CvPlot* pBestPlot = NULL;
	int iBestValue = 0;
	BuildTypes eBestBuild = NO_BUILD;
	CvPlot* pEndTurnPlot = NULL;
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (AI_plotValid(pLoopPlot) && pLoopPlot->area() == area())
		{
			if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
			{
				if (pLoopPlot->getFeatureType() != NO_FEATURE) 
				{
					// Determine if this feature is "fallout" (is it harming the plot significantly?)
					bool bFallout = GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_FOOD) < -2 && GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_PRODUCTION) < -2 && GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_COMMERCE) < -2;
					if (bFallout)
					{
						for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
						{
							if (GC.getBuildInfo((BuildTypes)iJ).isFeatureRemove(pLoopPlot->getFeatureType()))
							{
								if (canBuild(pLoopPlot, (BuildTypes)iJ))
								{
									int iPathTurns;
									if (generatePath(pLoopPlot, isHuman() ? 0 : MOVE_IGNORE_DANGER, true, &iPathTurns))
									{
										int iValue = 100000000;

										iValue /= (iPathTurns + 1);
										iValue /= (GC.getBuildInfo((BuildTypes)iJ).getFeatureTime(pLoopPlot->getFeatureType()) + 1);

										if (iValue > iBestValue)
										{
											iBestValue = iValue;
											eBestBuild = (BuildTypes)iJ;
											pBestPlot = pLoopPlot;
											pEndTurnPlot = getPathEndTurnPlot();
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL && pEndTurnPlot != NULL)
	{
		FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
		FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");

		if (!isHuman() &&
			(AI_workerNeedsToAwaitDefender(pBestPlot) ||
			AI_workerNeedsToAwaitDefender(pEndTurnPlot)))
		{
			return true;
		}

		if (getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), (isHuman() ? 0 : MOVE_WITH_CAUTION), false, false, MISSIONAI_BUILD, pBestPlot))
		{
			getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);

			return true;
		}
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_irrigateTerritory()
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pEndTurnPlot;
	ImprovementTypes eImprovement;
	BuildTypes eBuild;
	BuildTypes eBestBuild;
	BuildTypes eBestTempBuild;
	BonusTypes eNonObsoleteBonus;
	bool bValid;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iBestTempBuildValue;
	int iI, iJ;

	iBestValue = 0;
	eBestBuild = NO_BUILD;
	pBestPlot = NULL;

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (AI_plotValid(pLoopPlot) && pLoopPlot->area() == area())
		{
			if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
			{
				if (pLoopPlot->getWorkingCity() == NULL)
				{
					eImprovement = pLoopPlot->getImprovementType();

					if ((eImprovement == NO_IMPROVEMENT) || !(GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION) && !(eImprovement == (GC.getDefineINT("RUINS_IMPROVEMENT")))))
					{
						if ((eImprovement == NO_IMPROVEMENT) || !(GC.getImprovementInfo(eImprovement).isCarriesIrrigation()))
						{
							eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());

							if ((eImprovement == NO_IMPROVEMENT) || (eNonObsoleteBonus == NO_BONUS) || !(GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus)))
							{
								if (pLoopPlot->isIrrigationAvailable(true))
								{
									iBestTempBuildValue = MAX_INT;
									eBestTempBuild = NO_BUILD;

									for (iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
									{
										eBuild = ((BuildTypes)iJ);
										FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");

										if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
										{
											if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).isCarriesIrrigation())
											{
												if (canBuild(pLoopPlot, eBuild))
												{
													iValue = 10000;

													iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);

													// XXX feature production???

													if (iValue < iBestTempBuildValue)
													{
														iBestTempBuildValue = iValue;
														eBestTempBuild = eBuild;
													}
												}
											}
										}
									}

									if (eBestTempBuild != NO_BUILD)
									{
										bValid = true;

										if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS))
										{
											if (pLoopPlot->getFeatureType() != NO_FEATURE)
											{
												if (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType()))
												{
													if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_PRODUCTION) > 0)
													{
														bValid = false;
													}
												}
											}
										}

										if (bValid)
										{
											if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
											{
												if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1) == 0)
												{
													if (generatePath(pLoopPlot, isHuman() ? 0 : MOVE_IGNORE_DANGER, true, &iPathTurns)) // XXX should this actually be at the top of the loop? (with saved paths and all...)
													{
														iValue = 10000;

														iValue /= (iPathTurns + 1);

														if (iValue > iBestValue)
														{
															iBestValue = iValue;
															eBestBuild = eBestTempBuild;
															pBestPlot = pLoopPlot;
															pEndTurnPlot = getPathEndTurnPlot();
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
		FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");

		if ( !isHuman() &&
			 (AI_workerNeedsToAwaitDefender(pBestPlot) ||
			  AI_workerNeedsToAwaitDefender(pEndTurnPlot)))
		{
			return true;
		}

		if (getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), (isHuman() ? 0 : MOVE_WITH_CAUTION), false, false, MISSIONAI_BUILD, pBestPlot))
		{
			getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);

			return true;
		}
	}

	return false;
}


bool CvUnitAI::AI_fortTerritory(bool bCanal, bool bAirbase)
{
	PROFILE_FUNC();

	int iBestValue = 0;
	BuildTypes eBestBuild = NO_BUILD;
	CvPlot* pBestPlot = NULL;
	CvPlot* pEndTurnPlot;
/************************************************************************************************/
/* Afforess	                  Start		 08/02/10                                               */
/*                                                                                              */
/* Fixed Borders AI                                                                             */
/************************************************************************************************/
	if (AI_StrategicForts())
	{
		return true;
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), isHuman() ? 0 : MOVE_IGNORE_DANGER, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		CvPlot* pLoopPlot = itr.plot();
#else
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		if (/*AI_plotValid(pLoopPlot) &&*/ pLoopPlot->area() == area())
		{
			if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
			{
				if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
				{
					int iValue = 0;
					iValue += bCanal ? kOwner.AI_getPlotCanalValue(pLoopPlot) : 0;
					iValue += bAirbase ? kOwner.AI_getPlotAirbaseValue(pLoopPlot) : 0;

					if (iValue > 0)
					{
						int iBestTempBuildValue = MAX_INT;
						BuildTypes eBestTempBuild = NO_BUILD;

						for (int iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
						{
							BuildTypes eBuild = ((BuildTypes)iJ);
							FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");

							if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
							{
								if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).isActsAsCity())
								{
								    if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).getDefenseModifier() > 0)
								    {
                                        if (canBuild(pLoopPlot, eBuild))
                                        {
                                            iValue = 10000;

                                            iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);

                                            if (iValue < iBestTempBuildValue)
                                            {
                                                iBestTempBuildValue = iValue;
                                                eBestTempBuild = eBuild;
                                            }
                                        }
                                    }
								}
							}
						}

						if (eBestTempBuild != NO_BUILD)
						{
							if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
							{
								bool bValid = true;

								if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS))
								{
									if (pLoopPlot->getFeatureType() != NO_FEATURE)
									{
										if (GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType()))
										{
											if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).getYieldChange(YIELD_PRODUCTION) > 0)
											{
												bValid = false;
											}
										}
									}
								}

								if (bValid)
								{
									if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 3) == 0)
									{
										int iPathTurns;
										if (generatePath(pLoopPlot, isHuman() ? 0 : MOVE_IGNORE_DANGER, true, &iPathTurns))
										{
											iValue *= 1000;
											iValue /= (iPathTurns + 1);

											if (iValue > iBestValue)
											{
												iBestValue = iValue;
												eBestBuild = eBestTempBuild;
												pBestPlot = pLoopPlot;
												pEndTurnPlot = getPathEndTurnPlot();
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
		FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");

		if ( !isHuman() &&
			 (AI_workerNeedsToAwaitDefender(pBestPlot) ||
			  AI_workerNeedsToAwaitDefender(pEndTurnPlot)))
		{
			return true;
		}

		if (getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), (isHuman() ? 0 : MOVE_WITH_CAUTION), false, false, MISSIONAI_BUILD, pBestPlot))
		{
			getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);

			return true;
		}
	}
	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_improveBonus(int iMinValue, CvPlot** ppBestPlot, BuildTypes* peBestBuild, int* piBestValue)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pEndTurnPlot;
	ImprovementTypes eImprovement;
	BuildTypes eBuild;
	BuildTypes eBestBuild;
	BuildTypes eBestTempBuild;
	BonusTypes eNonObsoleteBonus;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iBestTempBuildValue;
	int iBestResourceValue;
	int iI, iJ;
	bool bBestBuildIsRoute = false;
	int iBasePathFlags = MOVE_SAFE_TERRITORY | MOVE_AVOID_ENEMY_UNITS | (isHuman() ? MOVE_OUR_TERRITORY : MOVE_IGNORE_DANGER | MOVE_RECONSIDER_ON_LEAVING_OWNED);

	bool bCanRoute;
	bool bIsConnected;

	static int iMaxDistFromBorder = -1;

	if ( -1 == iMaxDistFromBorder)
	{
		iMaxDistFromBorder = GC.getDefineINT("AI_WORKER_MAX_DISTANCE_FROM_CITY_OUT_BORDERS");
	}

	iBestValue = 0;
	iBestResourceValue = 0;
	eBestBuild = NO_BUILD;
	pBestPlot = NULL;

	bCanRoute = canBuildRoute();

	CvReachablePlotSet	plotSet(getGroup(), iBasePathFlags, -1, true, iMaxDistFromBorder/2+1);
	bool				bPlotSetPopulated = false;

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if ( bPlotSetPopulated && plotSet.find(pLoopPlot) == plotSet.end() )
		{
			continue;
		}

		if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE() && AI_plotValid(pLoopPlot))
		{
			PROFILE("CvUnitAI::AI_improveBonus.ConsiderPlot");
			bool bCanImprove = (pLoopPlot->area() == area());
			if (!bCanImprove)
			{
				if (DOMAIN_SEA == getDomainType() && pLoopPlot->isWater() && plot()->isAdjacentToArea(pLoopPlot->area()))
				{
					bCanImprove = true;
				}
			}

			if (bCanImprove)
			{
				eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());

				if (eNonObsoleteBonus != NO_BONUS)
				{
				    bIsConnected = pLoopPlot->isConnectedToCapital(getOwnerINLINE());
                    if (((pLoopPlot->getWorkingCity() != NULL) || (bIsConnected || bCanRoute)) && (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this)))
                    {
						PROFILE("CvUnitAI::AI_improveBonus.CheckImprovement");

                        eImprovement = pLoopPlot->getImprovementType();

                        bool bDoImprove = false;
                        
                        if (eImprovement == NO_IMPROVEMENT)
                        {
                            bDoImprove = true;
                        }
                        else if (GC.getImprovementInfo(eImprovement).isActsAsCity() || GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
                        {
                        	bDoImprove = false;
                        }
                        else if (eImprovement == (ImprovementTypes)(GC.getDefineINT("RUINS_IMPROVEMENT")))
                        {
                            bDoImprove = true;
                        }
                        else if (!GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_SAFE_AUTOMATION))
                        {
                        	bDoImprove = true;
                        }

                        iBestTempBuildValue = MAX_INT;
                        eBestTempBuild = NO_BUILD;

                        if (bDoImprove)
                        {
							PROFILE("CvUnitAI::AI_improveBonus.CheckBuild");

                            for (iJ = 0; iJ < GC.getNumBuildInfos(); iJ++)
                            {
                                eBuild = ((BuildTypes)iJ);

                                if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
                                {
                                    if (GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).isImprovementBonusTrade(eNonObsoleteBonus) || (!pLoopPlot->isCityRadius() && GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).isActsAsCity()))
                                    {
                                        if (canBuild(pLoopPlot, eBuild))
                                        {
                                        	if ((pLoopPlot->getFeatureType() == NO_FEATURE) || !GC.getBuildInfo(eBuild).isFeatureRemove(pLoopPlot->getFeatureType()) || !GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_LEAVE_FORESTS))
                                        	{
												iValue = 10000;

												iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);

												// XXX feature production???

												if (iValue < iBestTempBuildValue)
												{
													iBestTempBuildValue = iValue;
													eBestTempBuild = eBuild;
												}
                                        	}
                                        }
                                    }
                                }
                            }
                        }
                        if (eBestTempBuild == NO_BUILD)
                        {
                        	bDoImprove = false;
                        }

                        if ((eBestTempBuild != NO_BUILD) || (bCanRoute && !bIsConnected))
                        {
							if ( !bPlotSetPopulated )
							{
								plotSet.Populate(MAX_INT);

								bPlotSetPopulated = true;
								if ( plotSet.find(pLoopPlot) == plotSet.end() )
								{
									continue;
								}
							}

							PROFILE("CvUnitAI::AI_improveBonus.Evaluate");

							//	We use MOVE_IGNORE_DANGER in here so that the worker won't be spooked before it gets a chance
							//	to find a target plot (at which poin it will ask for an escort if necessary)
                        	if (generatePath(pLoopPlot, iBasePathFlags, true, &iPathTurns))
							{
								iValue = GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus);
											
								if (bDoImprove)
								{
									eImprovement = (ImprovementTypes)GC.getBuildInfo(eBestTempBuild).getImprovement();
									FAssert(eImprovement != NO_IMPROVEMENT);
									//iValue += (GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBestTempBuild).getImprovement()))
									iValue += 5 * pLoopPlot->calculateImprovementYieldChange(eImprovement, YIELD_FOOD, getOwnerINLINE(), false);
									iValue += 5 * pLoopPlot->calculateNatureYield(YIELD_FOOD, getTeam(), (pLoopPlot->getFeatureType() == NO_FEATURE) ? true : GC.getBuildInfo(eBestTempBuild).isFeatureRemove(pLoopPlot->getFeatureType()));
								}

								iValue += std::max(0, 100 * GC.getBonusInfo(eNonObsoleteBonus).getAIObjective());

								if (GET_PLAYER(getOwnerINLINE()).getNumTradeableBonuses(eNonObsoleteBonus) == 0)
								{
									iValue *= 2;
								}
								
								int iMaxWorkers = 1;
								if ((eBestTempBuild != NO_BUILD) && (!GC.getBuildInfo(eBestTempBuild).isKill()))
								{
									//allow teaming.
									iMaxWorkers = AI_calculatePlotWorkersNeeded(pLoopPlot, eBestTempBuild);
									if (getPathMovementRemaining() == 0)
									{
										iMaxWorkers = std::min((iMaxWorkers + 1) / 2, 1 + GET_PLAYER(getOwnerINLINE()).AI_baseBonusVal(eNonObsoleteBonus) / 20);
									}
								}
								
								if ((GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup()) < iMaxWorkers)
									&& (!bDoImprove || (pLoopPlot->getBuildTurnsLeft(eBestTempBuild, 0, 0) > (iPathTurns * 2 - 1))))
								{
									if (bDoImprove)
									{
										iValue *= 1000;
										
										if (atPlot(pLoopPlot))
										{
											iValue *= 3;
										}

										iValue /= (iPathTurns + 1);

										if (pLoopPlot->isCityRadius())
										{
											iValue *= 2;
										}

										if (iValue > iBestValue)
										{
											iBestValue = iValue;
											eBestBuild = eBestTempBuild;
											pBestPlot = pLoopPlot;
											pEndTurnPlot = getPathEndTurnPlot();
											bBestBuildIsRoute = false;
											iBestResourceValue = iValue;
										}
									}
									else
									{
										FAssert(bCanRoute && !bIsConnected);
										eImprovement = pLoopPlot->getImprovementType();
										if ((eImprovement != NO_IMPROVEMENT) && (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus)))
										{
											iValue *= 1000;
											iValue /= (iPathTurns + 1);
											
											if (iValue > iBestValue)
											{
												iBestValue = iValue;
												eBestBuild = NO_BUILD;
												pBestPlot = pLoopPlot;
												pEndTurnPlot = getPathEndTurnPlot();
												bBestBuildIsRoute = true;
											}
										}
									}
								}
                        	}
                        }
                    }
				}
			}
		}
	}
	
	if ((iBestValue < iMinValue) && (NULL != ppBestPlot))
	{
		FAssert(NULL != peBestBuild);
		FAssert(NULL != piBestValue);
		
		*ppBestPlot = pBestPlot;
		*peBestBuild = eBestBuild;
		*piBestValue = iBestResourceValue;
	}

	if (pBestPlot != NULL)
	{
		if (eBestBuild != NO_BUILD)
		{
			FAssertMsg(!bBestBuildIsRoute, "BestBuild should not be a route");
			FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
			
			if ( !isHuman() &&
				 (AI_workerNeedsToAwaitDefender(pBestPlot) ||
				  AI_workerNeedsToAwaitDefender(pEndTurnPlot)))
			{
				return true;
			}

			MissionTypes eBestMission = MISSION_MOVE_TO;
			
			if ((pBestPlot->getWorkingCity() == NULL) || !pBestPlot->getWorkingCity()->isConnectedToCapital())
			{
				eBestMission = MISSION_ROUTE_TO;
			}
			else
			{
				int iDistance = stepDistance(getX_INLINE(), getY_INLINE(), pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
				int iPathTurns;
				if (generatePath(pBestPlot, iBasePathFlags, false, &iPathTurns))
				{
					if (iPathTurns >= iDistance)
					{
						eBestMission = MISSION_ROUTE_TO;
					}
				}
			}
			eBestBuild = AI_betterPlotBuild(pBestPlot, eBestBuild);
			
			if (getGroup()->pushMissionInternal(eBestMission, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), (isHuman() ? 0 : MOVE_WITH_CAUTION), false, false, MISSIONAI_BUILD, pBestPlot) )
			{
				getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);

				return true;
			}
		}
		else if (bBestBuildIsRoute)
		{
			if (AI_connectPlot(pBestPlot))
			{
				return true;
			}
			/*else
			{
				// the plot may be connected, but not connected to capital, if capital is not on same area, or if civ has no capital (like barbarians)
				FAssertMsg(false, "Expected that a route could be built to eBestPlot");
			}*/
		}
		else
		{
			FAssert(false);
		}
	}

	return false;
}

bool CvUnitAI::AI_isAwaitingContract(void) const
{
	return (m_contractsLastEstablishedTurn == GC.getGameINLINE().getGameTurn() &&
			(m_contractualState == CONTRACTUAL_STATE_AWAITING_ANSWER || m_contractualState == CONTRACTUAL_STATE_AWAITING_WORK));
}

bool CvUnitAI::processContracts(int iMinPriority)
{
	PROFILE_FUNC();

	//	Currently not implemented for domains other than land
	if ( getDomainType() != DOMAIN_LAND )
	{
		return false;
	}

	bool bContractAlreadyEstablished = (m_contractsLastEstablishedTurn == GC.getGameINLINE().getGameTurn());

	//	Have we advertised ourselves as available yet?
	if ( !bContractAlreadyEstablished )
	{
		GET_PLAYER(getOwnerINLINE()).getContractBroker().lookingForWork(this, iMinPriority);

		m_contractsLastEstablishedTurn = GC.getGameINLINE().getGameTurn();
		m_contractualState = CONTRACTUAL_STATE_AWAITING_WORK;
		if( gUnitLogLevel >= 3 )
		{
			logBBAI("    Unit %S (%d) for player %d (%S) at (%d,%d) advertising for work\n",
					getUnitInfo().getDescription(),
					getID(),
					getOwner(),
					GET_PLAYER(getOwner()).getCivilizationDescription(0),
					plot()->getX_INLINE(),
					plot()->getY_INLINE());
		}
	}

	//TB OOS fix: Giving these a default seems to repair numerous OOS errors
	int		iAtX = 0;
	int		iAtY = 0;
	CvUnit*	pJoinUnit = NULL;

	if ( GET_PLAYER(getOwnerINLINE()).getContractBroker().makeContract(this, iAtX, iAtY, pJoinUnit, !bContractAlreadyEstablished) )
	{
		//	Work found
		if( gUnitLogLevel >= 3 )
		{
			logBBAI("    Unit %S (%d) for player %d (%S) at (%d,%d) found work at (%d,%d) [to join %d]\n",
					getUnitInfo().getDescription(),
					getID(),
					getOwner(),
					GET_PLAYER(getOwner()).getCivilizationDescription(0),
					plot()->getX_INLINE(),
					plot()->getY_INLINE(),
					iAtX,
					iAtY,
					(pJoinUnit == NULL ? -1 : pJoinUnit->getID()));
		}

		//	In rare circumstances it is possible that the unit that advertised for us may have itself actively
		//	jojned us, in which case we're done with this contract
		if ( pJoinUnit != NULL && pJoinUnit->getGroup() == getGroup() )
		{
			m_contractualState = CONTRACTUAL_STATE_FOUND_WORK;

			//	Remove ourselves from advertising for work and set our status back to no contract
			contractFulfilled();

			return true;
		}

		//	Must ungroup ourselves since it's just this unit that is answering the work
		//	request (unless it's a no-defend unit in which case it will go with any escorts it has)
		if (getGroup()->getNumUnits() > 1 && canDefend())
		{
			//	Also check we are not the ONLY unit that can defend - if we are we'll drag the rest along
			CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
			CvUnit* pLoopUnit = NULL;
			bool bHasOtherDefender = false;

			while( pUnitNode != NULL )
			{
				pLoopUnit = ::getUnit(pUnitNode->m_data);
				if ( pLoopUnit != this && pLoopUnit->canDefend() )
				{
					bHasOtherDefender = true;
					break;
				}

				pUnitNode = getGroup()->nextUnitNode(pUnitNode);
			}

			if ( bHasOtherDefender )
			{
				joinGroup(NULL);
			}
		}

		//	Try to enact the contracted work
		CvPlot*	pTargetPlot;

		if ( pJoinUnit != NULL )
		{
			pTargetPlot = pJoinUnit->plot();
		}
		else
		{
			pTargetPlot = GC.getMapINLINE().plotINLINE(iAtX,iAtY);
		}

		if (atPlot(pTargetPlot))
		{
			m_contractualState = CONTRACTUAL_STATE_FOUND_WORK;

			if ( pJoinUnit != NULL && atPlot(pJoinUnit->plot()) )
			{
				if( gUnitLogLevel >= 3 )
				{
					logBBAI("    ...already at target plot - merging into requesting unit's group.");
				}
				getGroup()->setTransportUnit(NULL);
				getGroup()->mergeIntoGroup(pJoinUnit->getGroup());

				//	Remove ourselves from advertising for work and set our status back to no contract
				contractFulfilled();
			}
			else
			{
				if( gUnitLogLevel >= 3 )
				{
					logBBAI("    ...already at target plot.");
				}
				getGroup()->pushMission(MISSION_SKIP);
			}
		}
		else
		{
			if ( !getGroup()->pushMissionInternal(MISSION_MOVE_TO, iAtX, iAtY, MOVE_SAFE_TERRITORY | MOVE_AVOID_ENEMY_UNITS, false, false, (pJoinUnit == NULL ? MISSIONAI_CONTRACT : MISSIONAI_CONTRACT_UNIT), pTargetPlot))
			{
				if( gUnitLogLevel >= 3 )
				{
					logBBAI("    ...unexpectedly unable to enact the work!");
				}

				//	Handle as if we found no work this turn since we cannot safely path to it
				m_contractualState = CONTRACTUAL_STATE_NO_WORK_FOUND;
				return false;
			}

			//	We only reset the contract establishment if we actively move to
			//	fulfill it.  This is so that:
			//	1)	In the move case, if the move doesn't use up all our movement allowance we can
			//		potentially recontract
			//	2)	In the non-move case we retain the knowledge that we've already looked and not found
			//		anything in particular to do - this prevents other units grouping with us and setting us back
			//		awake
			m_contractsLastEstablishedTurn = -1;
			m_contractualState = CONTRACTUAL_STATE_NONE;
		}

		return true;
	}
	else if ( bContractAlreadyEstablished )
	{
		m_contractualState = CONTRACTUAL_STATE_NO_WORK_FOUND;

		//	No work available
		if( gUnitLogLevel >= 3 )
		{
			logBBAI("    Unit %S (%d) for player %d (%S) at (%d,%d) - no work available",
					getUnitInfo().getDescription(),
					getID(),
					getOwner(),
					GET_PLAYER(getOwner()).getCivilizationDescription(0),
					plot()->getX_INLINE(),
					plot()->getY_INLINE());
		}

		return false;
	}

	return true;
}

void CvUnitAI::contractFulfilled(void)
{
	m_contractsLastEstablishedTurn = -1;	//	Contract fulfilled
	m_contractualState = CONTRACTUAL_STATE_NONE;

	GET_PLAYER(getOwnerINLINE()).getContractBroker().removeUnit(this);
}

bool CvUnitAI::AI_workerNeedsDefender(CvPlot* pPlot) const
{
	PROFILE_FUNC();

	//	Check danger level both where we are now and where we are headed
	int	iDanger = std::max(pPlot->getDangerCount(getOwnerINLINE()), plot()->getDangerCount(getOwnerINLINE()));

	//	Need to adjust this threshold based on experience with AI testing - 25 is an initial good guess
	if ( iDanger > 20 )
	{
		// Afforess - don't just return true, check for actual danger first!
		// return true;
		return GET_PLAYER(getOwnerINLINE()).AI_isPlotThreatened(plot(), 2);
	}

	//	Also for non-owned territory check for nearby enemies
	if ( pPlot->getOwner() != getOwnerINLINE() &&
		 GET_PLAYER(getOwnerINLINE()).AI_getVisiblePlotDanger(pPlot, 2, false) )
	{
		return true;
	}

	return false;
}

bool CvUnitAI::AI_workerNeedsToAwaitDefender(CvPlot* pPlot, int iMaxPath, bool skipOnWait)
{
	//	Currently not implemented for domains other than land
	if ( getDomainType() != DOMAIN_LAND )
	{
		return false;
	}

	//	Cargo units shouldn't be asking for escorts
	if ( isCargo() )
	{
		return false;
	}

    if (!(getGroup()->canDefend()))
	{
		if ( !AI_workerNeedsDefender(pPlot) )
		{
			return false;
		}

		//	If contracts are not yet established request defensive support
		if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )
		{
			//	For now adevrtise the work as being here since we'll be holding position
			//	while we wait for a defender.  It would be more optimal to 'meet' the defender
			//	on the way or at the target plot, but this might leave us exposed on the way so
			//	the calculations involved are somewhat harder and not attempted for now
			if( gUnitLogLevel >= 3 )
			{
				logBBAI("    Worker for player %d (%S) at (%d,%d) requesting defensive help to move to (%d,%d)",
						getOwner(),
						GET_PLAYER(getOwner()).getCivilizationDescription(0),
						plot()->getX_INLINE(),
						plot()->getY_INLINE(),
						pPlot->getX_INLINE(),
						pPlot->getY_INLINE());
			}

			GET_PLAYER(getOwnerINLINE()).getContractBroker().advertiseWork(LOW_PRIORITY_ESCORT_PRIORITY, DEFENSIVE_UNITCAPABILITIES, plot()->getX_INLINE(), plot()->getY_INLINE(), this, NO_UNITAI, -1, NULL, iMaxPath);

			m_contractsLastEstablishedTurn = GC.getGameINLINE().getGameTurn();
			m_contractualState = CONTRACTUAL_STATE_AWAITING_ANSWER;
		}
		else
		{
			if( gUnitLogLevel >= 3 )
			{
				logBBAI("    Worker for player %d (%S) at (%d,%d) awaiting defensive help to move to (%d,%d)",
						getOwner(),
						GET_PLAYER(getOwner()).getCivilizationDescription(0),
						plot()->getX_INLINE(),
						plot()->getY_INLINE(),
						pPlot->getX_INLINE(),
						pPlot->getY_INLINE());
			}

			if ( skipOnWait )
			{
				//	Sit tight 'til help arrives
				getGroup()->pushMission(MISSION_SKIP);
			}
			else
			{
				return false;
			}
		}

		return true;
	}

	return false;
}

bool CvUnitAI::AI_workerReleaseDefenderIfNotNeeded(void) const
{
	//	Never release on the same turn we contracted or an infinite loop can result
	if ( m_contractsLastEstablishedTurn != GC.getGameINLINE().getGameTurn() )
	{
		if ( getDomainType() != DOMAIN_LAND )
		{
			return false;
		}

		if (getGroup()->canDefend() && plot()->getOwnerINLINE() == getOwnerINLINE())
		{
			if ( !AI_workerNeedsDefender(plot()) )
			{
				CvSelectionGroup* pOldGroup = getGroup();

				if( gUnitLogLevel >= 3 )
				{
					logBBAI("    Worker for player %d (%S) at (%d,%d) releasing escort",
							getOwner(),
							GET_PLAYER(getOwner()).getCivilizationDescription(0),
							plot()->getX_INLINE(),
							plot()->getY_INLINE());
				}

				getGroup()->AI_makeForceSeparate();

				return true;
			}
		}
	}

	return false;
}

//returns true if a mission is pushed
//if eBuild is NO_BUILD, assumes a route is desired.
bool CvUnitAI::AI_improvePlot(CvPlot* pPlot, BuildTypes eBuild)
{
	PROFILE_FUNC();

	FAssert(pPlot != NULL);
	
	if (eBuild != NO_BUILD)
	{
		FAssertMsg(eBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");
		
		eBuild = AI_betterPlotBuild(pPlot, eBuild);
		if (!atPlot(pPlot))
		{
			if ( !getGroup()->pushMissionInternal(MISSION_MOVE_TO, pPlot->getX_INLINE(), pPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pPlot))
			{
				return false;
			}
		}
		getGroup()->pushMission(MISSION_BUILD, eBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pPlot);

		return true;
	}
	else if (canBuildRoute())
	{
		if (AI_connectPlot(pPlot))
		{
			return true;
		}
	}
	
	return false;
	
}

BuildTypes CvUnitAI::AI_betterPlotBuild(CvPlot* pPlot, BuildTypes eBuild)
{
	PROFILE_FUNC();

	FAssert(pPlot != NULL);
	FAssert(eBuild != NO_BUILD);
	bool bBuildRoute = false;
	bool bClearFeature = false;
	
	FeatureTypes eFeature = pPlot->getFeatureType();
	
	CvBuildInfo& kOriginalBuildInfo = GC.getBuildInfo(eBuild);
	
	if (kOriginalBuildInfo.getRoute() != NO_ROUTE)
	{
		return eBuild;
	}
	
	int iWorkersNeeded = AI_calculatePlotWorkersNeeded(pPlot, eBuild);
	
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						7/31/08				jdog5000	*/
	/* 																			*/
	/* 	Bugfix																	*/
	/********************************************************************************/
	//if ((pPlot->getBonusType() == NO_BONUS) && (pPlot->getWorkingCity() != NULL))
	if ((pPlot->getNonObsoleteBonusType(getTeam()) == NO_BONUS) && (pPlot->getWorkingCity() != NULL))
	{
		iWorkersNeeded = std::max(1, std::min(iWorkersNeeded, pPlot->getWorkingCity()->AI_getWorkersHave()));
	}
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						END								*/
	/********************************************************************************/

	if (eFeature != NO_FEATURE)
	{
		CvFeatureInfo& kFeatureInfo = GC.getFeatureInfo(eFeature);
		if (kOriginalBuildInfo.isFeatureRemove(eFeature))
		{
			if ((kOriginalBuildInfo.getImprovement() == NO_IMPROVEMENT) || (!pPlot->isBeingWorked() || (kFeatureInfo.getYieldChange(YIELD_FOOD) + kFeatureInfo.getYieldChange(YIELD_PRODUCTION)) <= 0))
			{
				bClearFeature = true;
			}
		}
		
		if ((kFeatureInfo.getMovementCost() > 1) && (iWorkersNeeded > 1))
		{
			bBuildRoute = true;
		}
	}
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						7/31/08				jdog5000	*/
	/* 																			*/
	/* 	Bugfix																	*/
	/********************************************************************************/
	//if (pPlot->getBonusType() != NO_BONUS)
	if (pPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
	{
		bBuildRoute = true;
	}
	else if (pPlot->isHills())
	{
		if ((GC.getHILLS_EXTRA_MOVEMENT() > 0) && (iWorkersNeeded > 1))
		{
			bBuildRoute = true;
		}
	}
	/********************************************************************************/
	/*		BETTER_BTS_AI_MOD						END								*/
	/********************************************************************************/
/************************************************************************************************/
/* Afforess	Mountains Start		 07/29/09                                           		 */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	else if (pPlot->isPeak())
	{
		if ((GC.getPEAK_EXTRA_MOVEMENT() > 0) && (iWorkersNeeded > 1))
		{
			bBuildRoute = true;
		}
	}
/************************************************************************************************/
/* Afforess	Mountains End       END        		                                             */
/************************************************************************************************/
	
	if (pPlot->getRouteType() != NO_ROUTE)
	{
		bBuildRoute = false;
	}
	
	BuildTypes eBestBuild = NO_BUILD;
	int iBestValue = 0;
	for (int iBuild = 0; iBuild < GC.getNumBuildInfos(); iBuild++)
	{
		BuildTypes eBuild = ((BuildTypes)iBuild);
		CvBuildInfo& kBuildInfo = GC.getBuildInfo(eBuild);
		
		
		RouteTypes eRoute = (RouteTypes)kBuildInfo.getRoute();
		if ((bBuildRoute && (eRoute != NO_ROUTE)) || (bClearFeature && kBuildInfo.isFeatureRemove(eFeature)))
		{
			if (canBuild(pPlot, eBuild))
			{
				int iValue = 10000;
				
				if (bBuildRoute && (eRoute != NO_ROUTE))
				{
					iValue *= (1 + GC.getRouteInfo(eRoute).getValue());
					iValue /= 2;
					
					/********************************************************************************/
					/* 	BETTER_BTS_AI_MOD						7/31/08				jdog5000	*/
					/* 																			*/
					/* 	Bugfix																	*/
					/********************************************************************************/
					//if if (pPlot->getBonusType() != NO_BONUS)
					if (pPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
					{
						iValue *= 2;
					}
					/********************************************************************************/
					/* 	BETTER_BTS_AI_MOD						END								*/
					/********************************************************************************/
					
					if (pPlot->getWorkingCity() != NULL)
					{
						iValue *= 2 + iWorkersNeeded + ((pPlot->isHills() && (iWorkersNeeded > 1)) ? 2 * GC.getHILLS_EXTRA_MOVEMENT() : 0);
						iValue /= 3;
					}
					ImprovementTypes eImprovement = (ImprovementTypes)kOriginalBuildInfo.getImprovement();
					if (eImprovement != NO_IMPROVEMENT)
					{
						int iRouteMultiplier = ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_FOOD)) * 100);
						iRouteMultiplier += ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_PRODUCTION)) * 100);
						iRouteMultiplier += ((GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eRoute, YIELD_COMMERCE)) * 60);
						iValue *= 100 + iRouteMultiplier;
						iValue /= 100;
					}
					
					int iPlotGroupId = -1;
					for (int iDirection = 0; iDirection < NUM_DIRECTION_TYPES; iDirection++)
					{
						CvPlot* pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), (DirectionTypes)iDirection);
						if (pLoopPlot != NULL)
						{
							if (pPlot->isRiver() || (pLoopPlot->getRouteType() != NO_ROUTE))
							{
								CvPlotGroup* pLoopGroup = pLoopPlot->getPlotGroup(getOwnerINLINE());
								if (pLoopGroup != NULL)
								{
									if (pLoopGroup->getID() != -1)
									{
										if (pLoopGroup->getID() != iPlotGroupId)
										{
											//This plot bridges plot groups, so route it.
											iValue *= 4;
											break;
										}
										else
										{
											iPlotGroupId = pLoopGroup->getID();
										}
									}
								}
							}
						}
					}	
				}

				iValue /= (kBuildInfo.getTime() + 1);

				if (iValue > iBestValue)
				{
					iBestValue = iValue;
					eBestBuild = eBuild;
				}
			}
		}
	}
	
	if (eBestBuild == NO_BUILD)
	{
		return eBuild;
	}
	return eBestBuild;	
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_connectBonus(bool bTestTrade)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	BonusTypes eNonObsoleteBonus;
	int iI;

	// XXX how do we make sure that we can build roads???

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
		{
			if (AI_plotValid(pLoopPlot) && pLoopPlot->area() == area())
			{
				eNonObsoleteBonus = pLoopPlot->getNonObsoleteBonusType(getTeam());

				if (eNonObsoleteBonus != NO_BONUS)
				{
					if (!(pLoopPlot->isConnectedToCapital()))
					{
						if (!bTestTrade || ((pLoopPlot->getImprovementType() != NO_IMPROVEMENT) && (GC.getImprovementInfo(pLoopPlot->getImprovementType()).isImprovementBonusTrade(eNonObsoleteBonus))))
						{
							if (AI_connectPlot(pLoopPlot))
							{
								return true;
							}
						}
					}
				}
			}
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_connectCity()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	int iLoop;

	// XXX how do we make sure that we can build roads???

    pLoopCity = plot()->getWorkingCity();
    if (pLoopCity != NULL)
    {
        if (AI_plotValid(pLoopCity->plot()))
        {
            if (!(pLoopCity->isConnectedToCapital()))
            {
                if (AI_connectPlot(pLoopCity->plot(), 1))
                {
                    return true;
                }
            }
        }
    }

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (AI_plotValid(pLoopCity->plot()))
		{
			if (!(pLoopCity->isConnectedToCapital()))
			{
				if (AI_connectPlot(pLoopCity->plot(), 1))
				{
					return true;
				}
			}
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_routeCity()
{
	PROFILE_FUNC();

	CvCity* pRouteToCity;
	CvCity* pLoopCity;
	int iLoop;
	int iBasePathFlags = MOVE_SAFE_TERRITORY | MOVE_AVOID_ENEMY_UNITS | (isHuman() ? MOVE_OUR_TERRITORY : MOVE_IGNORE_DANGER | MOVE_RECONSIDER_ON_LEAVING_OWNED);

	FAssert(canBuildRoute());

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (AI_plotValid(pLoopCity->plot()))
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/22/10                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
			// BBAI efficiency: check area for land units before generating path
			if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
			{
				continue;
			}

			pRouteToCity = pLoopCity->AI_getRouteToCity();

			if (pRouteToCity != NULL)
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
					if (!(pRouteToCity->plot()->isVisibleEnemyUnit(this)))
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pRouteToCity->plot(), MISSIONAI_BUILD, getGroup()) == 0)
						{
							if (generatePath(pLoopCity->plot(), iBasePathFlags, true))
							{
								if ( !isHuman() &&
									 (AI_workerNeedsToAwaitDefender(plot()) ||
									  AI_workerNeedsToAwaitDefender(getPathEndTurnPlot())))
								{
									return true;
								}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
								if (generatePath(pRouteToCity->plot(), iBasePathFlags, true))
								{
									if ( !isHuman() &&
										 (AI_workerNeedsToAwaitDefender(plot()) ||
										  AI_workerNeedsToAwaitDefender(getPathEndTurnPlot())))
									{
										return true;
									}

									if (getGroup()->pushMissionInternal(MISSION_ROUTE_TO, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), MOVE_SAFE_TERRITORY | MOVE_WITH_CAUTION, false, false, MISSIONAI_BUILD, pRouteToCity->plot()))
									{
										getGroup()->pushMission(MISSION_ROUTE_TO, pRouteToCity->getX_INLINE(), pRouteToCity->getY_INLINE(), MOVE_SAFE_TERRITORY | MOVE_WITH_CAUTION, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pRouteToCity->plot());

										return true;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_routeTerritory(bool bImprovementOnly)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	ImprovementTypes eImprovement;
	RouteTypes eBestRoute;
	bool bValid;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iI, iJ;

	// XXX how do we make sure that we can build roads???

	FAssert(canBuildRoute());

	iBestValue = 0;
	pBestPlot = NULL;

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()) // XXX team???
		{
			if (pLoopPlot->area() == area() && AI_plotValid(pLoopPlot))
			{
				/************************************************************************************************/
				/* Afforess	                  Start		 5/29/11                                                */
				/*                                                                                              */
				/*  Do not blindly rely on XML value, check movement info and route cost                        */
				/************************************************************************************************/
				eBestRoute = GET_PLAYER(getOwnerINLINE()).getBestRoute(pLoopPlot, false, this);
				/************************************************************************************************/
				/* Afforess	                     END                                                            */
				/************************************************************************************************/

				if (eBestRoute != NO_ROUTE)
				{
					if (eBestRoute != pLoopPlot->getRouteType())
					{
						if (bImprovementOnly)
						{
							bValid = false;

							eImprovement = pLoopPlot->getImprovementType();

							if (eImprovement != NO_IMPROVEMENT)
							{
								for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
								{
									if (GC.getImprovementInfo(eImprovement).getRouteYieldChanges(eBestRoute, iJ) > 0)
									{
										bValid = true;
										break;
									}
								}
							}
						}
						else
						{
							bValid = true;
						}

						if (bValid)
						{
							if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
							{
								if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 1) == 0)
								{
									if (generatePath(pLoopPlot, MOVE_SAFE_TERRITORY, true, &iPathTurns))
									{
										iValue = 10000;

										iValue /= (iPathTurns + 1);

										if (iValue > iBestValue)
										{
											iBestValue = iValue;
											pBestPlot = pLoopPlot;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_BUILD, pBestPlot);
		return true;
	}

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_travelToUpgradeCity()
{
	PROFILE_FUNC();

	// is there a city which can upgrade us?
	CvCity* pUpgradeCity = getUpgradeCity(/*bSearch*/ true);
	if (pUpgradeCity != NULL)
	{
		// cache some stuff
		CvPlot* pPlot = plot();
		bool bSeaUnit = (getDomainType() == DOMAIN_SEA);
		bool bCanAirliftUnit = (getDomainType() == DOMAIN_LAND);
		bool bShouldSkipToUpgrade = (getDomainType() != DOMAIN_AIR);

		// if we at the upgrade city, stop, wait to get upgraded
		if (pUpgradeCity->plot() == pPlot)
		{
			if (!bShouldSkipToUpgrade)
			{
				return false;
			}
			
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}

		if (DOMAIN_AIR == getDomainType())
		{
			FAssert(!atPlot(pUpgradeCity->plot()));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE());
		}

		// find the closest city
		CvCity* pClosestCity = pPlot->getPlotCity();
		bool bAtClosestCity = (pClosestCity != NULL);
		if (pClosestCity == NULL)
		{
			pClosestCity = pPlot->getWorkingCity();
		}
		if (pClosestCity == NULL)
		{
			pClosestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), NO_PLAYER, getTeam(), true, bSeaUnit);
		}

		// can we path to the upgrade city?
		int iUpgradeCityPathTurns;
		CvPlot* pThisTurnPlot = NULL;
		bool bCanPathToUpgradeCity = generatePath(pUpgradeCity->plot(), 0, true, &iUpgradeCityPathTurns);
		if (bCanPathToUpgradeCity)
		{
			pThisTurnPlot = getPathEndTurnPlot();
		}
		
		// if we close to upgrade city, head there 
		if (NULL != pThisTurnPlot && NULL != pClosestCity && (pClosestCity == pUpgradeCity || iUpgradeCityPathTurns < 4))
		{
			if ( !exposedToDanger(pThisTurnPlot, 70) )
			{
				FAssert(!atPlot(pThisTurnPlot));
				getGroup()->pushMission(MISSION_MOVE_TO, pThisTurnPlot->getX_INLINE(), pThisTurnPlot->getY_INLINE());
				return true;
			}
		}
		
		// check for better airlift choice
		if (bCanAirliftUnit && NULL != pClosestCity && pClosestCity->getMaxAirlift() > 0)
		{
			// if we at the closest city, then do the airlift, or wait
			if (bAtClosestCity)
			{
				// can we do the airlift this turn?
				if (canAirliftAt(pClosestCity->plot(), pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE()))
				{
					getGroup()->pushMission(MISSION_AIRLIFT, pUpgradeCity->getX_INLINE(), pUpgradeCity->getY_INLINE());
					return true;
				}
				// wait to do it next turn
				else
				{
					getGroup()->pushMission(MISSION_SKIP);
					return true;
				}
			}
			
			int iClosestCityPathTurns;
			CvPlot* pThisTurnPlotForAirlift = NULL;
			bool bCanPathToClosestCity = generatePath(pClosestCity->plot(), 0, true, &iClosestCityPathTurns);
			if (bCanPathToClosestCity)
			{
				pThisTurnPlotForAirlift = getPathEndTurnPlot();
			}
			
			// is the closest city closer pathing? If so, move toward closest city
			if (NULL != pThisTurnPlotForAirlift && (!bCanPathToUpgradeCity || iClosestCityPathTurns < iUpgradeCityPathTurns))
			{
				if ( !exposedToDanger(pThisTurnPlotForAirlift, 70) )
				{
					FAssert(!atPlot(pThisTurnPlotForAirlift));
					return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pThisTurnPlotForAirlift->getX_INLINE(), pThisTurnPlotForAirlift->getY_INLINE());
				}
			}
		}
		
		// did not have better airlift choice, go ahead and path to the upgrade city
		if (NULL != pThisTurnPlot)
		{
			if ( !exposedToDanger(pThisTurnPlot, 70) )
			{
				FAssert(!atPlot(pThisTurnPlot));
				return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pThisTurnPlot->getX_INLINE(), pThisTurnPlot->getY_INLINE());
			}
		}
	}

	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_retreatToCity(bool bPrimary, bool bAirlift, int iMaxPath)
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pLoopCity;
	CvPlot* pBestPlot = NULL;
	int iPathTurns;
	int iValue;
	int iBestValue = MAX_INT;
	int iPass;
	int iLoop;
	int iCurrentDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot());

	pCity = plot()->getPlotCity();

	if (0 == iCurrentDanger)
	{
		if (pCity != NULL)
		{
			if (pCity->getOwnerINLINE() == getOwnerINLINE())
			{
				if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pCity->area()))
				{
					if (!bAirlift || (pCity->getMaxAirlift() > 0))
					{
						if (!(pCity->plot()->isVisibleEnemyUnit(this)))
						{
							//	If we've successfully retreated and have an escort release it for now - the exceptions
							//	are generals who build up multiple escorts while in cities
							if ( !canDefend() && getGroup()->canDefend() && AI_getUnitAIType() != UNITAI_GENERAL )
							{
								joinGroup(NULL);
							}

							getGroup()->pushMission(MISSION_SKIP);
							return true;
						}
					}
				}
			}
		}
	}

	int iSearchRange = AI_searchRange(iMaxPath);

	for (iPass = 0; iPass < 4; iPass++)
	{
#ifdef USE_REACHABLE_ENUMERATION
		CvReachablePlotSet plotSet(getGroup(), (iPass > 1) ? MOVE_IGNORE_DANGER : 0, iSearchRange);
#endif

		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
#ifdef USE_REACHABLE_ENUMERATION
			if ( plotSet.find(pLoopCity->plot()) != plotSet.end() )
#else
			if (AI_plotValid(pLoopCity->plot()))
#endif
			{
				if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopCity->area()))
				{
					if (!bAirlift || (pLoopCity->getMaxAirlift() > 0))
					{
						if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
						{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
							// BBAI efficiency: check area for land units before generating path
							if( !bAirlift && (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
							{
								continue;
							}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

							if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), ((iPass > 1) ? MOVE_IGNORE_DANGER : 0), true, &iPathTurns))
							{
								if (iPathTurns <= ((iPass == 2) ? 1 : iMaxPath))
								{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
									if ((iPass > 0) || (getGroup()->canFight() || GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot()) < iCurrentDanger))
*/
									// Water units can't defend a city
									// Any unthreatened city acceptable on 0th pass, solves problem where sea units
									// would oscillate in and out of threatened city because they had iCurrentDanger = 0
									// on turns outside city
									
									bool bCheck = (iPass > 0) || (getGroup()->canDefend());
									if( !bCheck )
									{
										int iLoopDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pLoopCity->plot());
										bCheck = (iLoopDanger == 0) || (iLoopDanger < iCurrentDanger
											//Fuyu: try to avoid doomed cities
											&& iLoopDanger < 2*(pLoopCity->plot()->getNumDefenders(getOwnerINLINE())) );
									}
									
									if( bCheck )
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/		
									{
										iValue = iPathTurns;
										
										if (AI_getUnitAIType() == UNITAI_SETTLER_SEA)
										{
											iValue *= 1 + std::max(0, GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_SETTLE) - GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(pLoopCity->area(), UNITAI_SETTLER_SEA));
										}

										if (iValue < iBestValue)
										{
											CvPlot* endTurnPlot = getPathEndTurnPlot();

											if ( endTurnPlot == pLoopCity->plot() || !exposedToDanger(endTurnPlot, 60) )
											{
												iBestValue = iValue;
												pBestPlot = endTurnPlot;
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                      01/27/08                                jdog5000      */
	/*                                                                                              */
	/* Bugfix                                                                                       */
	/************************************************************************************************/
												// Not sure what can go wrong here, it seems somehow m_iData1 (moves) was set to 0
												// for first node in path so m_iData2 (turns) incremented
												if( atPlot(pBestPlot) )
												{
													//FAssert(false);
													pBestPlot = getGroup()->getPathFirstPlot();
													FAssert(!atPlot(pBestPlot));
												}
	/************************************************************************************************/
	/* BETTER_BTS_AI_MOD                       END                                                  */
	/************************************************************************************************/
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}

		if (pBestPlot != NULL)
		{
			break;
		}
		else if (iPass == 0)
		{
			if (pCity != NULL)
			{
				if (pCity->getOwnerINLINE() == getOwnerINLINE())
				{
					if (!bPrimary || GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pCity->area()))
					{
						if (!bAirlift || (pCity->getMaxAirlift() > 0))
						{
							if (!(pCity->plot()->isVisibleEnemyUnit(this)))
							{
								//	If we've successfully retreasted and have an escort release it for now
								if ( !canDefend() && getGroup()->canDefend() )
								{
									joinGroup(NULL);
								}

								getGroup()->pushMission(MISSION_SKIP);
								return true;
							}
						}
					}
				}
			}
		}

		if (getGroup()->alwaysInvisible())
		{
			break;
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((iPass > 0) ? MOVE_IGNORE_DANGER : 0));
	}

	if (pCity != NULL)
	{
		if (pCity->getTeam() == getTeam())
		{
			//	If we've successfully retreated and have an escort release it for now
			if ( !canDefend() && getGroup()->canDefend() )
			{
				joinGroup(NULL);
			}

			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
	}

	return false;
}


// Returns true if a mission was pushed...
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/15/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
bool CvUnitAI::AI_pickup(UnitAITypes eUnitAI)
*/
bool CvUnitAI::AI_pickup(UnitAITypes eUnitAI, bool bCountProduction, int iMaxPath)
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestPickupPlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
// Thomas SG - AC: Advanced Cargo START
	{
		FAssert(totalCargoSpace() > 0);
		if (0 == totalCargoSpace())
		{
			return false;
		}
	}
// Thomas SG - AC: Advanced Cargo END
	FAssert(cargoSpace() > 0);
	if (0 == cargoSpace())
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		if (pCity->getOwnerINLINE() == getOwnerINLINE())
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/23/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
/* original bts code
			if (pCity->plot()->plotCount(PUF_isUnitAIType, eUnitAI, -1, getOwnerINLINE()) > 0)
			{
				if ((AI_getUnitAIType() != UNITAI_ASSAULT_SEA) || pCity->AI_isDefended(-1))
				{
*/
			if( (GC.getGameINLINE().getGameTurn() - pCity->getGameTurnAcquired()) > 15 || (GET_TEAM(getTeam()).countEnemyPowerByArea(pCity->area()) == 0) )
			{
				bool bConsider = false;

				if(AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
				{
					// Improve island hopping
					if( pCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE )
					{
						bConsider = false;
					}
					else if( eUnitAI == UNITAI_ATTACK_CITY && !(pCity->AI_isDanger()) )
					{
						bConsider = (pCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_LAND) > pCity->AI_neededDefenders());
					}
					else
					{
						bConsider = pCity->AI_isDefended(-GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE));
					}
				}
				else if(AI_getUnitAIType() == UNITAI_SETTLER_SEA)
				{
					if( eUnitAI == UNITAI_CITY_DEFENSE )
					{
						bConsider = (pCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType) > 1);
					}
					else
					{
						bConsider = true;
					}
				}
				else
				{
					bConsider = true;
				}
				
				if ( bConsider )
				{
					// only count units which are available to load 
					int iCount = pCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, eUnitAI, -1, getOwnerINLINE(), NO_TEAM, PUF_isFiniteRange);
					
					if (bCountProduction && (pCity->getProductionUnitAI() == eUnitAI))
					{
						if( pCity->getProductionTurnsLeft() < 4 )
						{
							CvUnitInfo& kUnitInfo = GC.getUnitInfo(pCity->getProductionUnit());
							if ((kUnitInfo.getDomainType() != DOMAIN_AIR) || kUnitInfo.getAirRange() > 0)
							{
								iCount++;
							}
						}
					}
				// Thomas SG - AC: Advanced Cargo START
					iCount= 0;
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), MISSIONAI_PICKUP, getGroup()) < ((iCount + (totalCargoSpace() - 1)) / totalCargoSpace()))
						{
							getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_PICKUP, pCity->plot());
							return true;
						}
					}
				// Thomas SG - AC: Advanced Cargo END
				}
			}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
		}
	}

	iBestValue = 0;
	pBestPlot = NULL;
	pBestPickupPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (AI_plotValid(pLoopCity->plot()))
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      01/23/09                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
			if( (GC.getGameINLINE().getGameTurn() - pLoopCity->getGameTurnAcquired()) > 15 || (GET_TEAM(getTeam()).countEnemyPowerByArea(pLoopCity->area()) == 0) )
			{
				bool bConsider = false;

				if(AI_getUnitAIType() == UNITAI_ASSAULT_SEA)
				{
					if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE )
					{
						bConsider = false;
					}
					else if( eUnitAI == UNITAI_ATTACK_CITY && !(pLoopCity->AI_isDanger()) )
					{
						// Improve island hopping
						bConsider = (pLoopCity->plot()->plotCount(PUF_canDefend, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_LAND) > pLoopCity->AI_neededDefenders());
					}
					else
					{
						bConsider = pLoopCity->AI_isDefended(GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE));
					}
				}
				else if(AI_getUnitAIType() == UNITAI_SETTLER_SEA)
				{
					if( eUnitAI == UNITAI_CITY_DEFENSE )
					{
						bConsider = (pLoopCity->plot()->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE(), NO_TEAM, PUF_isCityAIType) > 1);
					}
					else
					{
						bConsider = true;
					}
				}
				else
				{
					bConsider = true;
				}

				if ( bConsider )
				{
					// only count units which are available to load, have had a chance to move since being built
					int iCount = pLoopCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, eUnitAI, -1, getOwnerINLINE(), NO_TEAM, (bCountProduction ? PUF_isFiniteRange : PUF_isFiniteRangeAndNotJustProduced));

					iValue = iCount * 10;
					
					if (bCountProduction && (pLoopCity->getProductionUnitAI() == eUnitAI))
					{
						CvUnitInfo& kUnitInfo = GC.getUnitInfo(pLoopCity->getProductionUnit());
						if ((kUnitInfo.getDomainType() != DOMAIN_AIR) || kUnitInfo.getAirRange() > 0)
						{
							iValue++;
							iCount++;
						}
					}

					if (iValue > 0)
					{
						iValue += pLoopCity->getPopulation();

						if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
						{
							// Thomas SG - AC: Advanced Cargo START
							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_PICKUP, getGroup()) < ((iCount + (totalCargoSpace() - 1)) / totalCargoSpace()))
							// Thomas SG - AC: Advanced Cargo END							
							{
								if( !(pLoopCity->AI_isDanger()) )
								{
									if (!atPlot(pLoopCity->plot()) && generatePath(pLoopCity->plot(), 0, true, &iPathTurns, iMaxPath))
									{
										if( AI_getUnitAIType() == UNITAI_ASSAULT_SEA )
										{
											if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT )
											{
												iValue *= 4;
											}
											else if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_ASSIST )
											{
												iValue *= 2;
											}
										}

										iValue *= 1000;

										iValue /= (iPathTurns + 3);

										if( (iValue > iBestValue) )
										{
											CvPlot* endTurnPlot = getPathEndTurnPlot();

											if ( endTurnPlot == pLoopCity->plot() || !exposedToDanger(endTurnPlot, 60) )
											{
												iBestValue = iValue;
												// Do one turn along path, then reevaluate
												// Causes update of destination based on troop movement
												//pBestPlot = pLoopCity->plot();
												pBestPlot = endTurnPlot;
												pBestPickupPlot = pLoopCity->plot();

												if( pBestPlot == NULL || atPlot(pBestPlot) )
												{
													//FAssert(false);
													pBestPlot = pBestPickupPlot;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	if ((pBestPlot != NULL) && (pBestPickupPlot != NULL))
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_PICKUP, pBestPickupPlot);
	}

	return false;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/22/10                                jdog5000      */
/*                                                                                              */
/* Naval AI                                                                                     */
/************************************************************************************************/
// Returns true if a mission was pushed...
bool CvUnitAI::AI_pickupStranded(UnitAITypes eUnitAI, int iMaxPath)
{
	PROFILE_FUNC();

	CvUnit* pBestUnit;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	int iCount;

	FAssert(cargoSpace() > 0);
	if (0 == cargoSpace())
	{
		return false;
	}

	if( isBarbarian() )
	{
		return false;
	}

	iBestValue = 0;
	pBestUnit = NULL;

	int iI;
	CvSelectionGroup* pLoopGroup = NULL;
	CvUnit* pHeadUnit = NULL;
	CvPlot* pLoopPlot = NULL;
	CvPlot* pPickupPlot = NULL;
	CvPlot* pAdjacentPlot = NULL;
	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());

	CvReachablePlotSet plotSet(getGroup(), MOVE_ALLOW_ADJACENT_COASTAL, AI_searchRange(iMaxPath));

	for(pLoopGroup = kPlayer.firstSelectionGroup(&iLoop); pLoopGroup != NULL; pLoopGroup = kPlayer.nextSelectionGroup(&iLoop))
	{
		if( pLoopGroup->isStranded() )
		{
			pHeadUnit = pLoopGroup->getHeadUnit();
			if( pHeadUnit == NULL )
			{
				continue;
			}

			if( (eUnitAI != NO_UNITAI) && (pHeadUnit->AI_getUnitAIType() != eUnitAI) )
			{
				continue;
			}

			pLoopPlot = pHeadUnit->plot();
			if( pLoopPlot == NULL  )
			{
				continue;
			}

			if( !(pLoopPlot->isCoastalLand())  && !canMoveAllTerrain() )
			{
				continue;
			}

			// Units are stranded, attempt rescue

			iCount = pLoopGroup->getNumUnits();
			
			if( 1000*iCount > iBestValue )
			{
				PROFILE("CvUnitAI::AI_pickupStranded.EvaluateTargetUnit");

				pPickupPlot = NULL;
				if( atPlot(pLoopPlot) )
				{
					pPickupPlot = pLoopPlot;
					iPathTurns = 0;
				}
				else if( plotSet.find(pLoopPlot) != plotSet.end() )
				{
					pPickupPlot = pLoopPlot;
				}
				else
				{
					if (pPickupPlot == NULL)
					{
						for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
						{
							pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));

							if (pAdjacentPlot != NULL && plotSet.find(pAdjacentPlot) != plotSet.end() )
							{
								//	If we can move into the target plot in one turn take account of whetehr an enemy unit is
								//	there (if it takes longer it might have moved away)
								if ( stepDistance(pAdjacentPlot->getX_INLINE(), pAdjacentPlot->getY_INLINE(), plot()->getX_INLINE(), plot()->getY_INLINE()) <= getMoves() || !pAdjacentPlot->isVisibleEnemyUnit(this) )
								{
									pPickupPlot = pAdjacentPlot;
									break;
								}
							}
						}
					}
				}

				MissionAITypes eMissionAIType = MISSIONAI_PICKUP;
				if( pPickupPlot != NULL )
				{
					iCount -= GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(pHeadUnit, &eMissionAIType, 1, getGroup(), iMaxPath == MAX_INT ? -1 : iMaxPath) * cargoSpace();

					iValue = 1000*iCount;

					int iMaxValuePath = (iBestValue == 0 ? MAX_INT : iValue/iBestValue);

					if( generatePath(pPickupPlot, 0, true, &iPathTurns, std::min(iMaxPath,iMaxValuePath)) )
					{
						iValue /= (iPathTurns + 1);

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestUnit = pHeadUnit;
						}
					}
				}
			}
		}
	}

	if ((pBestUnit != NULL))
	{
		if( atPlot(pBestUnit->plot()) )
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_PICKUP, pBestUnit->plot());
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestUnit->plot()));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO_UNIT, pBestUnit->getOwnerINLINE(), pBestUnit->getID(), MOVE_AVOID_ENEMY_WEIGHT_3, false, false, MISSIONAI_PICKUP, NULL, pBestUnit);
		}
	}

	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/


// Returns true if a mission was pushed...
bool CvUnitAI::AI_airOffensiveCity()
{
	//PROFILE_FUNC();

	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iI;

	FAssert(canAirAttack() || nukeRange() >= 0);

	iBestValue = 0;
	pBestPlot = NULL;

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						04/25/08			jdog5000		*/
/* 																				*/
/* 	Air AI																		*/
/********************************************************************************/
	/* original BTS code

	*/
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		// Limit to cities and forts, true for any city but only this team's forts
		if (pLoopPlot->isCity(true, getTeam()))
		{
			if (pLoopPlot->getTeam() == getTeam() || (pLoopPlot->isOwned() && GET_TEAM(pLoopPlot->getTeam()).isVassal(getTeam())))
			{
				if (atPlot(pLoopPlot) || canMoveInto(pLoopPlot))
				{
					iValue = AI_airOffenseBaseValue( pLoopPlot );

					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						pBestPlot = pLoopPlot;
					}
				}
			}
		}
	}
	
	if (pBestPlot != NULL)
	{
		if (!atPlot(pBestPlot))
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
		}
	}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END									*/
/********************************************************************************/

	return false;
}

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						04/25/10			jdog5000		*/
/* 																				*/
/* 	Air AI																		*/
/********************************************************************************/
// Function for ranking the value of a plot as a base for offensive air units
int CvUnitAI::AI_airOffenseBaseValue( CvPlot* pPlot )
{
	if( pPlot == NULL || pPlot->area() == NULL )
	{
		return 0;
	}

	CvCity* pNearestEnemyCity = NULL;
	int iRange = 0;
	int iTempValue = 0;
	int iOurDefense = 0;
	int iOurOffense = 0;
	int iEnemyOffense = 0;
	int iEnemyDefense = 0;
	int iDistance = 0;

	CvPlot* pLoopPlot = NULL;
	CvCity* pCity = pPlot->getPlotCity();

	int iDefenders = pPlot->plotCount(PUF_canDefend, -1, -1, pPlot->getOwner());

	int iAttackAirCount = pPlot->plotCount(PUF_canAirAttack, -1, -1, NO_PLAYER, getTeam());
	iAttackAirCount += 2 * pPlot->plotCount(PUF_isUnitAIType, UNITAI_ICBM, -1, NO_PLAYER, getTeam());
	if (atPlot(pPlot))
	{
		iAttackAirCount += canAirAttack() ? -1 : 0;
		iAttackAirCount += (nukeRange() >= 0) ? -2 : 0;
	}

	if( pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN()) )
	{
		iDefenders -= 1;
	}

	if( pCity != NULL )
	{
		if( pCity->getDefenseModifier(true) < 40 )
		{
			iDefenders -= 1;
		}

		if( pCity->getOccupationTimer() > 1 )
		{
			iDefenders -= 1;
		}
	}

	// Consider threat from nearby enemy territory
	iRange = 1;
	int iBorderDanger = 0;

	for (int iDX = -(iRange); iDX <= iRange; iDX++)
	{
		for (int iDY = -(iRange); iDY <= iRange; iDY++)
		{
			pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->area() == pPlot->area() && pLoopPlot->isOwned())
				{
				    iDistance = stepDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());
				    if( pLoopPlot->getTeam() != getTeam() && !(GET_TEAM(pLoopPlot->getTeam()).isVassal(getTeam())) )
					{
						if( iDistance == 1 )
						{
							iBorderDanger++;
						}

						if (atWar(pLoopPlot->getTeam(), getTeam()))
						{
							if (iDistance == 1)
							{
								iBorderDanger += 2;
							}
							else if ((iDistance == 2) && (pLoopPlot->isRoute()))
							{
								iBorderDanger += 2;
							}
						}
					}
				}
			}
		}
	}

	iDefenders -= std::min(2,(iBorderDanger + 1)/3);
	
	// Don't put more attack air units on plot than effective land defenders ... too large a risk
	if (iAttackAirCount >= (iDefenders) || iDefenders <= 0)
	{
		return 0;
	}
	
	bool bAnyWar = (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0);

	int iValue = 0;

	if( bAnyWar )
	{
		// Don't count assault assist, don't want to weight defending colonial coasts when homeland might be under attack
		bool bAssault = (pPlot->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT) || (pPlot->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_MASSING);

		// Loop over operational range
		iRange = airRange();

		for (int iDX = -(iRange); iDX <= iRange; iDX++)
		{
			for (int iDY = -(iRange); iDY <= iRange; iDY++)
			{
				pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);
				
				if ((pLoopPlot != NULL && pLoopPlot->area() != NULL))
				{
					iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());

					if( iDistance <= iRange )
					{
						bool bDefensive = pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE;
						bool bOffensive = pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE;

						// Value system is based around 1 enemy military unit in our territory = 10 pts
						iTempValue = 0;					

						if( pLoopPlot->isWater() )
						{
							if( pLoopPlot->isVisible(getTeam(),false) && !pLoopPlot->area()->isLake()  )
							{
								// Defend ocean
								iTempValue = 1;
								
								if( pLoopPlot->isOwned() )
								{
									if( pLoopPlot->getTeam() == getTeam() )
									{
										iTempValue += 1;
									}
									else if ((pLoopPlot->getTeam() != getTeam()) && GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN)
									{
										iTempValue += 1;
									}
								}

								// Low weight for visible ships cause they will probably move
								iTempValue += 2*pLoopPlot->getNumVisibleEnemyDefenders(this);

								if( bAssault )
								{
									iTempValue *= 2;
								}
							}
						}
						else 
						{
							if( !(pLoopPlot->isOwned()) )
							{
								if( iDistance < (iRange - 2) )
								{
									// Target enemy troops in neutral territory
									iTempValue += 4*pLoopPlot->getNumVisibleEnemyDefenders(this);
								}
							}
							else if( pLoopPlot->getTeam() == getTeam() )
							{
								iTempValue = 0;

								if( iDistance < (iRange - 2) )
								{
									// Target enemy troops in our territory
									iTempValue += 5*pLoopPlot->getNumVisibleEnemyDefenders(this);

									if( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() )
									{
										if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopPlot->area()) )
										{
											iTempValue *= 3;
										}
										else
										{
											iTempValue *= 2;
										}
									}

									if( bDefensive )
									{
										iTempValue *= 2;
									}
								}
							}
							else if ((pLoopPlot->getTeam() != getTeam()) && GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN)
							{
								// Attack opponents land territory
								iTempValue = 3;

								CvCity* pLoopCity = pLoopPlot->getPlotCity();

								if (pLoopCity != NULL)
								{
									// Target enemy cities
									iTempValue += (3*pLoopCity->getPopulation() + 30);

									if( canAirBomb(pPlot) && pLoopCity->isBombardable(this) )
									{
										iTempValue *= 2;
									}

									if( pLoopPlot->area()->getTargetCity(getOwnerINLINE()) == pLoopCity )
									{
										iTempValue *= 2;
									}

									if( pLoopCity->AI_isDanger() )
									{
										// Multiplier for nearby troops, ours, teammate's, and any other enemy of city
										iTempValue *= 3;
									}
								}
								else
								{
									if( iDistance < (iRange - 2) )
									{
										// Support our troops in enemy territory
										iTempValue += 15*pLoopPlot->getNumDefenders(getOwnerINLINE());

										// Target enemy troops adjacent to our territory
										if( pLoopPlot->isAdjacentTeam(getTeam(),true) )
										{
											iTempValue += 7*pLoopPlot->getNumVisibleEnemyDefenders(this);
										}
									}

									// Weight resources
									if (canAirBombAt(pPlot, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
									{
										if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
										{
											iTempValue += 8*std::max(2, GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(getTeam()))/10);
										}
									}
								}

								if( (pLoopPlot->area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) )
								{
									// Extra weight for enemy territory in offensive areas
									iTempValue *= 2;
								}

								if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopPlot->area()) )
								{
									iTempValue *= 3;
									iTempValue /= 2;
								}

								if( pLoopPlot->isBarbarian() )
								{
									iTempValue /= 2;
								}
							}
						}

						iValue += iTempValue;
					}
				}
			}
		}

		// Consider available defense, direct threat to potential base
		iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pPlot,0,true,false,true);	
		iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pPlot,2,false,false);

		if( 3*iEnemyOffense > iOurDefense || iOurDefense == 0 )
		{
			iValue *= iOurDefense;
			iValue /= std::max(1,3*iEnemyOffense);
		}

		// Value forts less, they are generally riskier bases
		if( pCity == NULL )
		{
			iValue *= 2;
			iValue /= 3;
		}
	}
	else
	{
		if( pPlot->getOwnerINLINE() != getOwnerINLINE() )
		{
			// Keep planes at home when not in real wars
			return 0;
		}

		// If no wars, use prior logic with added value to keeping planes safe from sneak attack
		if (pCity != NULL)
		{
			iValue = (pCity->getPopulation() + 20);
			iValue += pCity->AI_cityThreat();
		}
		else
		{
			if( iDefenders > 0 )
			{
				iValue = (pCity != NULL) ? 0 : GET_PLAYER(getOwnerINLINE()).AI_getPlotAirbaseValue(pPlot);
				iValue /= 6;
			}
		}

		iValue += std::min(24, 3*(iDefenders - iAttackAirCount));

		if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pPlot->area()) )
		{
			iValue *= 4;
			iValue /= 3;
		}

		// No real enemies, check for minor civ or barbarian cities where attacks could be supported
		pNearestEnemyCity = GC.getMapINLINE().findCity(pPlot->getX_INLINE(), pPlot->getY_INLINE(), NO_PLAYER, NO_TEAM, false, false, getTeam());

		if (pNearestEnemyCity != NULL)
		{
			iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pNearestEnemyCity->getX_INLINE(), pNearestEnemyCity->getY_INLINE());
			if (iDistance > airRange())
			{
				iValue /= 10 * (2 + airRange());
			}
			else
			{
				iValue /= 2 + iDistance;
			}
		}
	}
	
	if (pPlot->getOwnerINLINE() == getOwnerINLINE())
	{
		// Bases in our territory better than teammate's
		iValue *= 2;
	}
	else if( pPlot->getTeam() == getTeam() )
	{
		// Our team's bases are better than vassal plots
		iValue *= 3;
		iValue /= 2;
	}

	return iValue;
}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

// Returns true if a mission was pushed...
bool CvUnitAI::AI_airDefensiveCity()
{
	//PROFILE_FUNC();

	CvCity* pCity;
	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iLoop;

	FAssert(getDomainType() == DOMAIN_AIR);
	FAssert(canAirDefend());

	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						10/26/08			jdog5000	*/
	/* 																			*/
	/* 	Air AI																	*/
	/********************************************************************************/
	if (canAirDefend() && getDamage() == 0)
	{
		pCity = plot()->getPlotCity();

		if (pCity != NULL)
		{
			if (pCity->getOwnerINLINE() == getOwnerINLINE())
			{
				if ( !(pCity->AI_isAirDefended(false,+1)) )
				{
					// Stay if very short on planes, regardless of situation
					getGroup()->pushMission(MISSION_AIRPATROL);
					return true;
				}
				
				if( !(pCity->AI_isAirDefended(true,-1)) )
				{
					// Stay if city is threatened but not seriously threatened
					int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),2,false,false);
				
					if (iEnemyOffense > 0)
					{
						int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),0,true,false,true);
						if( 3*iEnemyOffense < 4*iOurDefense )
						{
							getGroup()->pushMission(MISSION_AIRPATROL);
							return true;
						}
					}
				}
			}
		}
	}
	
	iBestValue = 0;
	pBestPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if (canAirDefend(pLoopCity->plot()))
		{
			if (atPlot(pLoopCity->plot()) || canMoveInto(pLoopCity->plot()))
			{
				int iExistingAirDefenders = pLoopCity->plot()->plotCount(PUF_canAirDefend, -1, -1, pLoopCity->getOwnerINLINE(), NO_TEAM, PUF_isDomainType, DOMAIN_AIR);
				if( atPlot(pLoopCity->plot()) )
				{
					iExistingAirDefenders -= 1;
				}
				int iNeedAirDefenders = pLoopCity->AI_neededAirDefenders();
			
				if ( iNeedAirDefenders > iExistingAirDefenders )
				{
					iValue = pLoopCity->getPopulation() + pLoopCity->AI_cityThreat();

					int iOurDefense = GET_TEAM(getTeam()).AI_getOurPlotStrength(pLoopCity->plot(),0,true,false,true);
					int iEnemyOffense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pLoopCity->plot(),2,false,false);
				
					iValue *= 100;

					// Increase value of cities needing air defense more
					iValue *= std::max(1, 3 + iNeedAirDefenders - iExistingAirDefenders);

					if( GET_PLAYER(getOwnerINLINE()).AI_isPrimaryArea(pLoopCity->area()) )
					{
						iValue *= 4;
						iValue /= 3;
					}

					// Reduce value of endangered city, it may be too late to help
					if (3*iEnemyOffense > iOurDefense || iOurDefense == 0)
					{
						iValue *= iOurDefense;
						iValue /= std::max(1,3*iEnemyOffense);
					}

					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						pBestPlot = pLoopCity->plot();
					}
				}
			}
		}
	}

	if (pBestPlot != NULL && !atPlot(pBestPlot))
	{
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						END								*/
	/********************************************************************************/

	return false;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_airCarrier()
{
	//PROFILE_FUNC();

	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	int iValue;
	int iBestValue;
	int iLoop;

	if (getCargo() > 0)
	{
		return false;
	}

	if (isCargo())
	{
		if (canAirDefend())
		{
			getGroup()->pushMission(MISSION_AIRPATROL);
			return true;
		}
		else
		{
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
	}

	iBestValue = 0;
	pBestUnit = NULL;

	for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
	{
		if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
		{
			iValue = 10;

			if (!(pLoopUnit->plot()->isCity()))
			{
				iValue += 20;
			}

			if (pLoopUnit->plot()->isOwned())
			{
				if (isEnemy(pLoopUnit->plot()->getTeam(), pLoopUnit->plot()))
				{
					iValue += 20;
				}
			}
			else
			{
				iValue += 10;
			}

			iValue /= (pLoopUnit->getCargo() + 1);

			if (iValue > iBestValue)
			{
				iBestValue = iValue;
				pBestUnit = pLoopUnit;
			}
		}
	}

	if (pBestUnit != NULL)
	{
		if (atPlot(pBestUnit->plot()))
		{
			setTransportUnit(pBestUnit); // XXX is this dangerous (not pushing a mission...) XXX air units?
			return true;
		}
		else
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE());
		}
	}

	return false;
}

bool CvUnitAI::AI_missileLoad(UnitAITypes eTargetUnitAI, int iMaxOwnUnitAI, bool bStealthOnly)
{
	//PROFILE_FUNC();

	CvUnit* pBestUnit = NULL;
	int iBestValue = 0;
	int iLoop;
	CvUnit* pLoopUnit;
	for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
	{
		if (!bStealthOnly || pLoopUnit->getInvisibleType() != NO_INVISIBLE)
		{
			if (pLoopUnit->AI_getUnitAIType() == eTargetUnitAI)
			{
				if ((iMaxOwnUnitAI == -1) || (pLoopUnit->getUnitAICargo(AI_getUnitAIType()) <= iMaxOwnUnitAI))
				{
					if (canLoadUnit(pLoopUnit, pLoopUnit->plot()))
					{
						int iValue = 100;
						
						iValue += GC.getGame().getSorenRandNum(100, "AI missile load");

						iValue *= 1 + pLoopUnit->getCargo();

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestUnit = pLoopUnit;
						}
					}
				}
			}
		}
	}

	if (pBestUnit != NULL)
	{
		if (atPlot(pBestUnit->plot()))
		{
			setTransportUnit(pBestUnit); // XXX is this dangerous (not pushing a mission...) XXX air units?
			return true;
		}
		else
		{
			if ( getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestUnit->getX_INLINE(), pBestUnit->getY_INLINE()))
			{
				setTransportUnit(pBestUnit);
				return true;
			}
		}
	}

	return false;	
	
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_airStrike()
{
	//PROFILE_FUNC();

	CvUnit* pDefender;
	CvUnit* pInterceptor;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iDamage;
	int iPotentialAttackers;
	int iInterceptProb;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iSearchRange = airRange();

	iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (5 * m_pUnitInfo->getProductionCost()) / 6 : 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (canMoveInto(pLoopPlot, true))
				{
					iValue = 0;
					iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
					if (pLoopPlot->isCity())
					{
						iPotentialAttackers += GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_ASSAULT, getGroup(), 1) * 2;							
					}
					/********************************************************************************/
					/* 	BETTER_BTS_AI_MOD						10/13/08		jdog5000		*/
					/* 																			*/
					/* 	Air AI																	*/
					/********************************************************************************/
					/* original BTS code
					if (pLoopPlot->isWater() || (iPotentialAttackers > 0) || pLoopPlot->isAdjacentTeam(getTeam()))
					*/
					// Bombers will always consider striking units adjacent to this team's territory
					// to soften them up for potential attack.  This situation doesn't apply if this team's adjacent
					// territory is water, land units won't be able to reach easily for attack
					if (pLoopPlot->isWater() || (iPotentialAttackers > 0) || pLoopPlot->isAdjacentTeam(getTeam(),true))
					/********************************************************************************/
					/* 	BETTER_BTS_AI_MOD						END								*/
					/********************************************************************************/
					{
						pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

						FAssert(pDefender != NULL);
						FAssert(pDefender->canDefend());

						// XXX factor in air defenses...

						iDamage = airCombatDamage(pDefender);

						iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));

						iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);

						iValue *= (3 + iPotentialAttackers);
						iValue /= 4;

						pInterceptor = bestInterceptor(pLoopPlot);

						if (pInterceptor != NULL)
						{
							iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();

							iInterceptProb *= std::max(0, (100 - evasionProbability()));
							iInterceptProb /= 100;

							iValue *= std::max(0, 100 - iInterceptProb / 2);
							iValue /= 100;
						}
						
						if (pLoopPlot->isWater())
						{
							iValue *= 3;
						}

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;
							FAssert(!atPlot(pBestPlot));
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}

/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						9/16/08			jdog5000		*/
/* 																			*/
/* 	Air AI																	*/
/********************************************************************************/
// Air strike focused on weakening enemy stacks threatening our cities
// Returns true if a mission was pushed...
bool CvUnitAI::AI_defensiveAirStrike()
{
	PROFILE_FUNC();

	CvUnit* pDefender;
	CvUnit* pInterceptor;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iDamage;
	int iInterceptProb;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iSearchRange = airRange();

	iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (60 * m_pUnitInfo->getProductionCost()) : 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (canMoveInto(pLoopPlot, true)) // Only true of plots this unit can airstrike
				{
					// Only attack enemy land units near our cities
					if( pLoopPlot->isPlayerCityRadius(getOwnerINLINE()) && !pLoopPlot->isWater() )
					{
						CvCity* pClosestCity = GC.getMapINLINE().findCity(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), getOwnerINLINE(), getTeam(), true, false);

						if( pClosestCity != NULL )
						{
							// City and pLoopPlot forced to be in same area, check they're still close
							int iStepDist = plotDistance(pClosestCity->getX_INLINE(), pClosestCity->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE());

							if( iStepDist < 3 )
							{
								iValue = 0;

								pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

								FAssert(pDefender != NULL);
								FAssert(pDefender->canDefend());

								iDamage = airCombatDamage(pDefender);

								iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));

								iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);

								iValue *= GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pClosestCity->plot(),2,false,false);
								iValue /= std::max(1, GET_TEAM(getTeam()).AI_getOurPlotStrength(pClosestCity->plot(),0,true,false,true));

								if( iStepDist == 1 )
								{
									iValue *= 5;
									iValue /= 4;
								}

								pInterceptor = bestInterceptor(pLoopPlot);

								if (pInterceptor != NULL)
								{
									iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();

									iInterceptProb *= std::max(0, (100 - evasionProbability()));
									iInterceptProb /= 100;

									iValue *= std::max(0, 100 - iInterceptProb / 2);
									iValue /= 100;
								}

								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = pLoopPlot;
									FAssert(!atPlot(pBestPlot));
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}

// Air strike around base city
// Returns true if a mission was pushed...
bool CvUnitAI::AI_defendBaseAirStrike()
{
	PROFILE_FUNC();

	CvUnit* pDefender;
	CvUnit* pInterceptor;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iDamage;
	int iInterceptProb;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	// Only search around base
	int iSearchRange = 2;

	iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (15 * m_pUnitInfo->getProductionCost()) : 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (canMoveInto(pLoopPlot, true) && !pLoopPlot->isWater()) // Only true of plots this unit can airstrike
				{
					if( plot()->area() == pLoopPlot->area() )
					{
						iValue = 0;

						pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

						FAssert(pDefender != NULL);
						FAssert(pDefender->canDefend());

						iDamage = airCombatDamage(pDefender);

						iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));

						iValue += ((iDamage * collateralDamage()) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / (2*100);

						// Weight towards stronger units
						iValue *= (pDefender->currCombatStr(NULL,NULL,NULL) + 2000);
						iValue /= 2000;

						// Weight towards adjacent stacks
						if( plotDistance(plot()->getX_INLINE(), plot()->getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) == 1 )
						{
							iValue *= 5;
							iValue /= 4;
						}

						pInterceptor = bestInterceptor(pLoopPlot);

						if (pInterceptor != NULL)
						{
							iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();

							iInterceptProb *= std::max(0, (100 - evasionProbability()));
							iInterceptProb /= 100;

							iValue *= std::max(0, 100 - iInterceptProb / 2);
							iValue /= 100;
						}

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;
							FAssert(!atPlot(pBestPlot));
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}
/********************************************************************************/
/* 	BETTER_BTS_AI_MOD						END								*/
/********************************************************************************/

bool CvUnitAI::AI_airBombPlots()
{
	//PROFILE_FUNC();

	CvUnit* pInterceptor;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iInterceptProb;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iSearchRange = airRange();

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (!pLoopPlot->isCity() && pLoopPlot->isOwned() && pLoopPlot != plot())
				{
					if (canAirBombAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						iValue = 0;

						if (pLoopPlot->getBonusType(pLoopPlot->getTeam()) != NO_BONUS)
						{
							iValue += AI_pillageValue(pLoopPlot, 15);

							iValue += GC.getGameINLINE().getSorenRandNum(10, "AI Air Bomb");
						}
						else if (isSuicide())
						{
							//This should only be reached when the unit is desperate to die
							iValue += AI_pillageValue(pLoopPlot);
							// Guided missiles lean towards destroying resource-producing tiles as opposed to improvements like Towns
							if (pLoopPlot->getBonusType(pLoopPlot->getTeam()) != NO_BONUS)
							{
								//and even more so if it's a resource
								iValue += GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(pLoopPlot->getTeam()));
							}
						}

						if (iValue > 0)
						{

							pInterceptor = bestInterceptor(pLoopPlot);

							if (pInterceptor != NULL)
							{
								iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();

								iInterceptProb *= std::max(0, (100 - evasionProbability()));
								iInterceptProb /= 100;

								iValue *= std::max(0, 100 - iInterceptProb / 2);
								iValue /= 100;
							}

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopPlot;
								FAssert(!atPlot(pBestPlot));
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_AIRBOMB, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}

	return false;
}	


bool CvUnitAI::AI_airBombDefenses()
{
	//PROFILE_FUNC();

	CvCity* pCity;
	CvUnit* pInterceptor;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPotentialAttackers;
	int iInterceptProb;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iSearchRange = airRange();

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				pCity = pLoopPlot->getPlotCity();
				if (pCity != NULL)
				{
					iValue = 0;

					if (canAirBombAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
						iPotentialAttackers += std::max(0, GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pCity->plot(), NO_MISSIONAI, getGroup(), 2) - 4);

						if (iPotentialAttackers > 1)
						{
							iValue += std::max(0, (std::min((pCity->getDefenseDamage() + airBombCurrRate()), GC.getMAX_CITY_DEFENSE_DAMAGE()) - pCity->getDefenseDamage()));

							iValue *= 4 + iPotentialAttackers;

							if (pCity->AI_isDanger())
							{
								iValue *= 2;
							}

							if (pCity == pCity->area()->getTargetCity(getOwnerINLINE()))
							{
								iValue *= 2;
							}
						}
						
						if (iValue > 0)
						{
							pInterceptor = bestInterceptor(pLoopPlot);

							if (pInterceptor != NULL)
							{
								iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();

								iInterceptProb *= std::max(0, (100 - evasionProbability()));
								iInterceptProb /= 100;

								iValue *= std::max(0, 100 - iInterceptProb / 2);
								iValue /= 100;
							}

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopPlot;
								FAssert(!atPlot(pBestPlot));
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_AIRBOMB, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}

	return false;	
	
}

bool CvUnitAI::AI_exploreAir()
{
	PROFILE_FUNC();
	
	CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
	int iLoop;
	CvCity* pLoopCity;
	CvPlot* pBestPlot = NULL;
	int iBestValue = 0;
	
	for (int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive() && !GET_PLAYER((PlayerTypes)iI).isBarbarian())
		{
			if (GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
			{
				for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
				{
					if (!pLoopCity->isVisible(getTeam(), false))
					{
						if (canReconAt(plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
						{
							int iValue = 1 + GC.getGame().getSorenRandNum(15, "AI explore air");
							if (isEnemy(GET_PLAYER((PlayerTypes)iI).getTeam()))
							{
								iValue += 10;
								iValue += std::min(10,  pLoopCity->area()->getNumAIUnits(getOwnerINLINE(), UNITAI_ATTACK_CITY));
								iValue += 10 * kPlayer.AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_ASSAULT);
							}
							
							iValue *= plotDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE());
							
							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopCity->plot();								
							}
						}
					}
				}
			}
		}
	}
	
	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_RECON, pBestPlot->getX(), pBestPlot->getY());
		return true;
	}
	
	return false;	
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      06/02/09                                jdog5000      */
/*                                                                                              */
/* Player Interface                                                                             */
/************************************************************************************************/
int CvUnitAI::AI_exploreAirPlotValue( CvPlot* pPlot )
{
	int iValue = 0;
	if (pPlot->isVisible(getTeam(), false))
	{
		iValue++;

		if (!pPlot->isOwned())
		{
			iValue++;
		}

	/************************************************************************************************/
		/* Afforess	Mountains Start		 09/18/09                                           		 */
		/*                                                                                              */
		/*                                                                                              */
	/************************************************************************************************/
		if (!pPlot->isImpassable(getTeam())) // added getTeam()
	/************************************************************************************************/
		/* Afforess	Mountains End       END        		                                             */
	/************************************************************************************************/
		{
			iValue *= 4;

			if (pPlot->isWater() || pPlot->getArea() == getArea())
			{
				iValue *= 2;
			}
		}
	}

	return iValue;
}

bool CvUnitAI::AI_exploreAir2()
{
	PROFILE_FUNC();
	
	CvPlayer& kPlayer = GET_PLAYER(getOwner());
	CvPlot* pLoopPlot = NULL;
	CvPlot* pBestPlot = NULL;
	int iBestValue = 0;

	int iDX, iDY;
	int iSearchRange = airRange();
	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if( pLoopPlot != NULL )
			{
				if( !pLoopPlot->isVisible(getTeam(),false) )
				{
					if (canReconAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						int iValue = AI_exploreAirPlotValue( pLoopPlot );

						for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
						{
							DirectionTypes eDirection = (DirectionTypes) iI;
							CvPlot* pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), eDirection);
							if (pAdjacentPlot != NULL)
							{
								if( !pAdjacentPlot->isVisible(getTeam(),false) )
								{
									iValue += AI_exploreAirPlotValue( pAdjacentPlot );
								}
							}
						}

						iValue += GC.getGame().getSorenRandNum(25, "AI explore air");
						iValue *= std::min(7, plotDistance(getX_INLINE(), getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()));
		
						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;								
						}
					}
				}
			}
		}
	}
	
	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_RECON, pBestPlot->getX(), pBestPlot->getY());
		return true;
	}
	
	return false;	
}

void CvUnitAI::AI_exploreAirMove()
{
	if( AI_exploreAir() )
	{
		return;
	}

	if( AI_exploreAir2() )
	{
		return;
	}

	if( canAirDefend() )
	{
		getGroup()->pushMission(MISSION_AIRPATROL);
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

/************************************************************************************************/
/* Great Diplomat MOD               START                                                  		*/
/************************************************************************************************/
void CvUnitAI::AI_diplomat()
{
	if ((GC.getGame().getGameTurn() - getGameTurnCreated()) > 25)
	{
		if (AI_goldenAge())
        {
            return;
        }

		if (AI_discover())
		{
			return;
		}

		if (AI_join())
		{
			return;
		}
	}

	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (pPlot != NULL)
		{
			if (canMoveInto(pPlot, false, false, true))
			{
				if (atPlot(pPlot))
				{
					if (canUpgradeImprovements(pPlot, COMMAND_UPGRADE_IMPROVEMENTS))
					{
						upgradeImprovements(pPlot, COMMAND_UPGRADE_IMPROVEMENTS);
						return;
					}
				}
			}
		}
	}
	CvCity* pBestCity = NULL;
	CvCity* pLoopCity;
	CvPlot* pLoopPlot;
	int iValue;
	int iBestValue = 0;
	int iLoop;

	if (AI_forcePeace(1, 5))
	{
		return;
	}

	iBestValue = 0;
	if (pBestCity == NULL)
	{
		int num_plots = GC.getMapINLINE().numPlotsINLINE();
		for (iI = 0; iI < num_plots; iI++)
		{
			pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
			if (pLoopPlot->isRevealed(getTeam(), false))
			{
				pLoopCity = pLoopPlot->getPlotCity();
				if (pLoopCity != NULL)
				{
					if (pLoopCity->isBarbarian())
					{
						iValue = std::max(1, GC.getGameINLINE().getSorenRandNum(pLoopCity->getPopulation(), "AI Politician colonize barbs"));
						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestCity = pLoopCity;
						}
					}
				}
			}
		}
		if (pBestCity != NULL)
		{
			if (GC.getGameINLINE().getSorenRandNum((pBestCity->getPopulation() * 10), "AI Politician colonize barbs") < 20)
			{
				if (atPlot(pBestCity->plot()))
				{
					if (canColonizeBarbarians(plot()))
					{
						colonizeBarbarians();
						return;
					}
				}
				else
				{
					FAssert(!atPlot(pBestCity->plot()));
					getGroup()->pushMission(MISSION_MOVE_TO, pBestCity->getX_INLINE(), pBestCity->getY_INLINE());
					return;
				}
			}
			else
			{
				pBestCity = NULL;
			}
		}
	}

	if (pBestCity == NULL)
	{
		iValue = 0;
		iBestValue = ((NUM_CITY_PLOTS * 2) / 3);

		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
			iValue = 0;

			for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
			{
				pLoopPlot = pLoopCity->getCityIndexPlot(iI);

				if (pLoopPlot != NULL && pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
				{
					iValue += GC.getCommandInfo(COMMAND_UPGRADE_IMPROVEMENTS).getUpgradeImprovementRate((int)pLoopPlot->getImprovementType());
				}
			}

			if (iValue > iBestValue)
			{
				iBestValue = iValue;
				pBestCity = pLoopCity;
			}
		}

		if (pBestCity != NULL)
		{
			if (atPlot(pBestCity->plot()))
			{
				upgradeImprovements(plot(), COMMAND_UPGRADE_IMPROVEMENTS);
				return;
			}
			else
			{
				FAssert(!atPlot(pBestCity->plot()));
				getGroup()->pushMission(MISSION_MOVE_TO, pBestCity->getX_INLINE(), pBestCity->getY_INLINE());
				return;
			}
		}
	}
	//AI for Goodwill Mission by Stolenrays Start
	iBestValue = 0;
	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive() && !GET_PLAYER((PlayerTypes)iI).isBarbarian())
		{
			if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) <= ATTITUDE_FRIENDLY)
			{
				for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
				{
					if (canMoveInto(plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
					{
						iValue = GET_PLAYER(getOwnerINLINE()).AI_getPeaceWeight();

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestCity = pLoopCity;
							FAssert(pBestCity->getTeam() != getTeam());
						}
					}
				}
			}
			if (pBestCity != NULL)
			{
				if (atPlot(pBestCity->plot()))
				{
					Goodwill();
					return;
				}
				else
				{
					FAssert(!atPlot(pBestCity->plot()));
					getGroup()->pushMission(MISSION_MOVE_TO, pBestCity->getX_INLINE(), pBestCity->getY_INLINE());
					return;
				}
			}
		}
	}
	//AI for Goodwill Mission by Stolenrays End
	if (pBestCity == NULL)
	{
		int iGoldenAgeValue = (GET_PLAYER(getOwnerINLINE()).AI_calculateGoldenAgeValue() / (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge()));
		int iDiscoverValue = std::max(1, getDiscoverResearch(NO_TECH));

		if (((iGoldenAgeValue * 100) / iDiscoverValue) > 60)
		{
	        if (AI_goldenAge())
	        {
	            return;
	        }

	        if (iDiscoverValue > iGoldenAgeValue)
	        {
	            if (AI_discover())
	            {
	                return;
	            }
	            if (GET_PLAYER(getOwnerINLINE()).getUnitClassCount(getUnitClassType()) > 1)
	            {
	                if (AI_join())
	                {
	                    return;
	                }
	            }
	        }
		}
		else
		{
			if (AI_discover())
			{
				return;
			}

			if (AI_join())
			{
				return;
			}
		}

		if (AI_retreatToCity())
		{
			return;
		}

		if (AI_safety())
		{
			return;
		}
	}
	getGroup()->pushMission(MISSION_SKIP);
	return;
}


// Returns true if a mission was pushed...
bool CvUnitAI::AI_forcePeace(int iAdditionalPeaceWeight, int iAttitudeMultiplier)
{
	if (!canForcePeace())
	{
		return false;
	}

	PlayerTypes eBestPlayer = NO_PLAYER;
	int iValue;
	int iBestValue = 0;
	int iPeaceWeight = GET_PLAYER(getOwnerINLINE()).AI_getPeaceWeight() + iAdditionalPeaceWeight;
	int iCount = 0;

	for (int iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive())
		{
			if (canForcePeaceWith((PlayerTypes)iI))
			{
				iValue = GC.getGame().getSorenRandNum(iPeaceWeight * std::max(0, (GET_TEAM(getTeam()).AI_endWarVal(GET_PLAYER((PlayerTypes)iI).getTeam()) - GET_TEAM(GET_PLAYER((PlayerTypes)iI).getTeam()).AI_endWarVal(getTeam()))), "AI force peace");

				if (iValue > iBestValue)
				{
					iBestValue = iValue;
					eBestPlayer = (PlayerTypes)iI;
					iCount++;
				}
			}
		}
	}

	if (eBestPlayer != NO_PLAYER && iCount != 0)
	{
		if (GC.getGame().getSorenRandNum((GET_PLAYER(getOwnerINLINE()).AI_getAttitude(eBestPlayer) * iAttitudeMultiplier), "AI attitude force peace") < (iPeaceWeight))
		{
			applyForcePeace(eBestPlayer);
			return true;
		}
	}

	return false;
}
/************************************************************************************************/
/* Great Diplomat MOD               END                                                  		*/
/************************************************************************************************/

// Returns true if a mission was pushed...
bool CvUnitAI::AI_nuke()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvCity* pBestCity;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;

	pBestCity = NULL;

	iBestValue = 0;

	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive() && !GET_PLAYER((PlayerTypes)iI).isBarbarian())
		{
			if (isEnemy(GET_PLAYER((PlayerTypes)iI).getTeam()))
			{
				if (GET_PLAYER(getOwnerINLINE()).AI_getAttitude((PlayerTypes)iI) == ATTITUDE_FURIOUS)
				{
					for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
					{
						if (canNukeAt(plot(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE()))
						{
							iValue = AI_nukeValue(pLoopCity);

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestCity = pLoopCity;
								FAssert(pBestCity->getTeam() != getTeam());
							}
						}
					}
				}
			}
		}
	}

	if (pBestCity != NULL)
	{
		getGroup()->pushMission(MISSION_NUKE, pBestCity->getX_INLINE(), pBestCity->getY_INLINE());
		return true;
	}

	return false;
}

bool CvUnitAI::AI_nukeRange(int iRange)
{
	CvPlot* pBestPlot = NULL;
	int iBestValue = 0;
	for (int iDX = -(iRange); iDX <= iRange; iDX++)
	{
		for (int iDY = -(iRange); iDY <= iRange; iDY++)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
			
			if (pLoopPlot != NULL)
			{
				if (canNukeAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
				{
					int iValue = -99;
					
					for (int iDX2 = -(nukeRange()); iDX2 <= nukeRange(); iDX2++)
					{
						for (int iDY2 = -(nukeRange()); iDY2 <= nukeRange(); iDY2++)
						{
							CvPlot* pLoopPlot2 = plotXY(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), iDX2, iDY2);

							if (pLoopPlot2 != NULL)
							{
								int iEnemyCount = 0;
								int iTeamCount = 0;
								int iNeutralCount = 0;
								int iDamagedEnemyCount = 0;
								
								CLLNode<IDInfo>* pUnitNode;
								CvUnit* pLoopUnit;
								pUnitNode = pLoopPlot2->headUnitNode();
								while (pUnitNode != NULL)
								{
									pLoopUnit = ::getUnit(pUnitNode->m_data);
									pUnitNode = pLoopPlot2->nextUnitNode(pUnitNode);
									
									if (!pLoopUnit->isNukeImmune())
									{
										if (pLoopUnit->getTeam() == getTeam())
										{
											iTeamCount++;
										}
										else if (!pLoopUnit->isInvisible(getTeam(), false))
										{
											if (isEnemy(pLoopUnit->getTeam()))
											{
												iEnemyCount++;
												if (pLoopUnit->getDamage() * 2 > pLoopUnit->maxHitPoints())
												{
													iDamagedEnemyCount++;
												}
											}
											else
											{
												iNeutralCount++;
											}
										}
									}
								}
								
								iValue += (iEnemyCount + iDamagedEnemyCount) * (pLoopPlot2->isWater() ? 25 : 12);
								iValue -= iTeamCount * 15;
								iValue -= iNeutralCount * 20;
								
								
								int iMultiplier = 1;
								if (pLoopPlot2->getTeam() == getTeam())
								{
									iMultiplier = -2;
								}
								else if (isEnemy(pLoopPlot2->getTeam()))
								{
									iMultiplier = 1;
								}
								else if (!pLoopPlot2->isOwned())
								{
									iMultiplier = 0;
								}
								else
								{
									iMultiplier = -10;
								}
								
								if (pLoopPlot2->getImprovementType() != NO_IMPROVEMENT)
								{
									iValue += iMultiplier * 10;
								}

								/********************************************************************************/
								/* 	BETTER_BTS_AI_MOD						7/31/08				jdog5000	*/
								/* 																			*/
								/* 	Bugfix																	*/
								/********************************************************************************/
								// This could also have been considered a minor AI cheat
								//if (pLoopPlot2->getBonusType() != NO_BONUS)
								if (pLoopPlot2->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
								{
									iValue += iMultiplier * 20;
								}
								/********************************************************************************/
								/* 	BETTER_BTS_AI_MOD						END								*/
								/********************************************************************************/
								
								if (pLoopPlot2->isCity())
								{
									iValue += std::max(0, iMultiplier * (-20 + 15 * pLoopPlot2->getPlotCity()->getPopulation()));
								}
							}
						}
					}
					
					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						pBestPlot = pLoopPlot;
					}
				}
			}
		}
	}
	
	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_NUKE, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}
	
	return false;
}

bool CvUnitAI::AI_trade(int iValueThreshold)
{
	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestTradePlot;

	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;


	iBestValue = 0;
	pBestPlot = NULL;
	pBestTradePlot = NULL;

	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive())
		{
			for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
			{
				if (AI_plotValid(pLoopCity->plot()))
				{
                    if (getTeam() != pLoopCity->getTeam())
				    {
                        iValue = getTradeGold(pLoopCity->plot());

                        if ((iValue >= iValueThreshold) && canTrade(pLoopCity->plot(), true))
                        {
                            if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
                            {
                                if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
                                {
                                    iValue /= (4 + iPathTurns);

                                    if (iValue > iBestValue)
                                    {
                                        iBestValue = iValue;
                                        pBestPlot = getPathEndTurnPlot();
                                        pBestTradePlot = pLoopCity->plot();
                                    }
                                }

                            }
                        }
				    }
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestTradePlot != NULL))
	{
		if (atPlot(pBestTradePlot))
		{
			getGroup()->pushMission(MISSION_TRADE);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		}
	}

	return false;
}

bool CvUnitAI::AI_infiltrate()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;

	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;

	iBestValue = 0;
	pBestPlot = NULL;
	
	if (canInfiltrate(plot()))
	{
		getGroup()->pushMission(MISSION_INFILTRATE);
		return true;
	}
	
	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if ((GET_PLAYER((PlayerTypes)iI).isAlive()) && GET_PLAYER((PlayerTypes)iI).getTeam() != getTeam())
		{
			for (pLoopCity = GET_PLAYER((PlayerTypes)iI).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER((PlayerTypes)iI).nextCity(&iLoop))
			{
				if (canInfiltrate(pLoopCity->plot()))
				{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/22/10                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
					// BBAI efficiency: check area for land units before generating path
					if( (getDomainType() == DOMAIN_LAND) && (pLoopCity->area() != area()) && !(getGroup()->canMoveAllTerrain()) )
					{
						continue;
					}

					iValue = getEspionagePoints(pLoopCity->plot());
					
					if (iValue > iBestValue)
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
					{
						if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
						{
							FAssert(iPathTurns > 0);
							
							if (getPathMovementRemaining() == 0)
							{
								iPathTurns++;
							}

							iValue /= 1 + iPathTurns;

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopCity->plot();
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL))
	{
		if (atPlot(pBestPlot))
		{
			getGroup()->pushMission(MISSION_INFILTRATE);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			if (getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE()))
			{
				getGroup()->pushMission(MISSION_INFILTRATE, -1, -1, 0, (getGroup()->getLengthMissionQueue() > 0));
				return true;
			}
		}
	}

	return false;
}

bool CvUnitAI::AI_reconSpy(int iRange)
{
	PROFILE_FUNC();
	CvPlot* pLoopPlot;
	int iX, iY;
	
	CvPlot* pBestPlot = NULL;
	CvPlot* pBestTargetPlot = NULL;
	int iBestValue = 0;
	
	int iSearchRange = AI_searchRange(iRange);

	for (iX = -iSearchRange; iX <= iSearchRange; iX++)
	{
		for (iY = -iSearchRange; iY <= iSearchRange; iY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
			int iDistance = stepDistance(0, 0, iX, iY);
			if ((iDistance > 0) && (pLoopPlot != NULL) && AI_plotValid(pLoopPlot))
			{
				int iValue = 0;
				if (pLoopPlot->getPlotCity() != NULL)
				{
					iValue += GC.getGameINLINE().getSorenRandNum(4000, "AI Spy Scout City");
				}
				
				if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
				{
					iValue += GC.getGameINLINE().getSorenRandNum(1000, "AI Spy Recon Bonus");
				}
				
				for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
				{
					CvPlot* pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));

					if (pAdjacentPlot != NULL)
					{
						if (!pAdjacentPlot->isRevealed(getTeam(), false))
						{
							iValue += 500;
						}
						else if (!pAdjacentPlot->isVisible(getTeam(), false))
						{
							iValue += 200;
						}
					}
				}


				if (iValue > 0)
				{
					int iPathTurns;
					if (generatePath(pLoopPlot, 0, true, &iPathTurns, iRange))
					{
						if (iPathTurns <= iRange)
						{
							// don't give each and every plot in range a value before generating the patch (performance hit)
							iValue += GC.getGameINLINE().getSorenRandNum(250, "AI Spy Scout Best Plot");

							iValue *= iDistance;

							/* Can no longer perform missions after having moved
							if (getPathLastNode()->m_iData2 == 1)
							{
								if (getPathLastNode()->m_iData1 > 0)
								{
									//Prefer to move and have movement remaining to perform a kill action.
									iValue *= 2;
								}
							} */

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestTargetPlot = getPathEndTurnPlot();
								pBestPlot = pLoopPlot;
							}
						}
					}
				}
			}
		}
	}
	
	if ((pBestPlot != NULL) && (pBestTargetPlot != NULL))
	{
		if (atPlot(pBestTargetPlot))
		{
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
		else
		{
			if (getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestTargetPlot->getX_INLINE(), pBestTargetPlot->getY_INLINE()))	
			{
				getGroup()->pushMission(MISSION_SKIP);
				return true;
			}
		}
	}
	
	return false;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      10/25/09                               jdog5000        */
/*                                                                                               */
/* Espionage AI                                                                                  */
/************************************************************************************************/
/// \brief Spy decision on whether to cause revolt in besieged city
///
/// Have spy breakdown city defenses if we have troops in position to capture city this turn.
bool CvUnitAI::AI_revoltCitySpy()
{
	PROFILE_FUNC();

	CvCity* pCity = plot()->getPlotCity();

	FAssert(pCity != NULL);

	if( pCity == NULL )
	{
		return false;
	}

	if( !(GET_TEAM(getTeam()).isAtWar(pCity->getTeam())) )
	{
		return false;
	}

	if( pCity->isDisorder() )
	{
		return false;
	}

	int iOurPower = GET_PLAYER(getOwnerINLINE()).AI_getOurPlotStrength(plot(),1,false,true);
	int iEnemyDefensePower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,true,false);
	int iEnemyPostPower = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(plot(),0,false,false);

	if( iOurPower > 2*iEnemyDefensePower )
	{
		return false;
	}

	if( iOurPower < iEnemyPostPower )
	{
		return false;
	}

	if( 10*iEnemyDefensePower < 11*iEnemyPostPower )
	{
		return false;
	}

	for (int iMission = 0; iMission < GC.getNumEspionageMissionInfos(); ++iMission)
	{
		CvEspionageMissionInfo& kMissionInfo = GC.getEspionageMissionInfo((EspionageMissionTypes)iMission);
		if ((kMissionInfo.getCityRevoltCounter() > 0) || (kMissionInfo.getPlayerAnarchyCounter() > 0))
		{
			if (!GET_PLAYER(getOwnerINLINE()).canDoEspionageMission((EspionageMissionTypes)iMission, pCity->getOwnerINLINE(), pCity->plot(), -1, this))
			{
				continue;
			}
			
			if (!espionage((EspionageMissionTypes)iMission, -1))
			{
				continue;
			}

			return true;
		}
	}

	return false;
}

int CvUnitAI::AI_getEspionageTargetValue(CvPlot* pPlot, int iMaxPath, int iMinUsefulValue)
{
	PROFILE_FUNC();

	CvTeamAI& kTeam = GET_TEAM(getTeam());
	int iValue = 0;

	if (pPlot->isOwned() && pPlot->getTeam() != getTeam() && !GET_TEAM(getTeam()).isVassal(pPlot->getTeam()))
	{
		if (AI_plotValid(pPlot))
		{
			CvCity* pCity = pPlot->getPlotCity();
			if (pCity != NULL)
			{
				iValue += pCity->getPopulation();
				iValue += pCity->plot()->calculateCulturePercent(getOwnerINLINE())/8;

				// BBAI TODO: Should go to cities where missions will be cheaper ...

				int iRand = GC.getGame().getSorenRandNum(6, "AI spy choose city");
				iValue += iRand * iRand;

				if( area()->getTargetCity(getOwnerINLINE()) == pCity )
				{
					iValue += 30;
				}

				if( GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_ASSAULT, getGroup()) > 0 )
				{
					iValue += 30;
				}

				// BBAI TODO: What else?  If can see production, go for wonders and space race ...
			}
			else
			{
				BonusTypes eBonus = pPlot->getNonObsoleteBonusType(getTeam());
				if (eBonus != NO_BONUS)
				{
					iValue += GET_PLAYER(pPlot->getOwnerINLINE()).AI_baseBonusVal(eBonus) - 10;
				}
			}

			int iPathableValue = iValue;
			if (kTeam.AI_getWarPlan(pPlot->getTeam()) != NO_WARPLAN)
			{
				if (kTeam.AI_isSneakAttackPreparing(pPlot->getTeam()))
				{
					iPathableValue *= (pPlot->isCity()) ? 15 : 10;						
				}
				else
				{
					iPathableValue *= 3;
				}
			}

			iPathableValue *= 3;
			iPathableValue /= (3 + GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pPlot, MISSIONAI_ATTACK_SPY, getGroup()));

			int iPathTurns;
			if (iPathableValue > iMinUsefulValue && generatePath(pPlot, 0, true, &iPathTurns, iMaxPath))
			{
				iValue = iPathableValue;
			}
			else
			{
				iValue = 0;
			}
		}
	}

	return (iValue > iMinUsefulValue) ? iValue : 0;
}


bool CvUnitAI::AI_cityOffenseSpy(int iMaxPath, CvCity* pSkipCity)
{
	PROFILE_FUNC();

	int iBestValue = 0;
	CvPlot* pBestPlot = NULL;

	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; ++iPlayer)
	{
		CvPlayer& kLoopPlayer = GET_PLAYER((PlayerTypes)iPlayer);
		if (kLoopPlayer.isAlive() && kLoopPlayer.getTeam() != getTeam() && !GET_TEAM(getTeam()).isVassal(kLoopPlayer.getTeam()))
		{
			// Only move to cities where we will run missions
			if (GET_PLAYER(getOwnerINLINE()).AI_getAttitudeWeight((PlayerTypes)iPlayer) < (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 51 : 1)
				|| GET_TEAM(getTeam()).AI_getWarPlan(kLoopPlayer.getTeam()) != NO_WARPLAN
				|| GET_TEAM(getTeam()).getBestKnownTechScorePercent() < 85 )
			{
				int iLoop;
				for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); NULL != pLoopCity; pLoopCity = kLoopPlayer.nextCity(&iLoop))
				{
					if( pLoopCity == pSkipCity )
					{
						continue;
					}

					if (pLoopCity->area() == area() || canMoveAllTerrain())
					{
						CvPlot* pLoopPlot = pLoopCity->plot();
						if (plotSet.find(pLoopPlot) != plotSet.end())
						{
							int iValue = AI_getEspionageTargetValue(pLoopPlot, iMaxPath, iBestValue);
							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopPlot;								
							}
						}
					}
				}
			}
		}
	}
	
	if (pBestPlot != NULL)
	{
		if (atPlot(pBestPlot))
		{
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
			return true;
		}
		else
		{
			if ( getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY ))
			{
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
				return true;
			}
		}
	}
	
	return false;
}

bool CvUnitAI::AI_bonusOffenseSpy(int iRange)
{
	PROFILE_FUNC();

	CvPlot* pBestPlot = NULL;

	int iBestValue = 10;

	int iSearchRange = AI_searchRange(iRange);

	for (int iX = -iSearchRange; iX <= iSearchRange; iX++)
	{
		for (int iY = -iSearchRange; iY <= iSearchRange; iY++)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);

			if (NULL != pLoopPlot && pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
			{
				if( pLoopPlot->isOwned() && pLoopPlot->getTeam() != getTeam() )
				{
					// Only move to plots where we will run missions
					if (GET_PLAYER(getOwnerINLINE()).AI_getAttitudeWeight(pLoopPlot->getOwner()) < (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 51 : 1)
						|| GET_TEAM(getTeam()).AI_getWarPlan(pLoopPlot->getTeam()) != NO_WARPLAN )
					{
						int iValue = AI_getEspionageTargetValue(pLoopPlot, iRange, iBestValue);
						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;								
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		if (atPlot(pBestPlot))
		{	
			getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
			return true;
		}
		else
		{
			if ( getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_ATTACK_SPY))
			{
				getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_ATTACK_SPY);
				return true;
			}
		}
	}

	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

//Returns true if the spy performs espionage.
bool CvUnitAI::AI_espionageSpy()
{
	PROFILE_FUNC();

	if (!canEspionage(plot()))
	{
		return false;
	}
	
	EspionageMissionTypes eBestMission = NO_ESPIONAGEMISSION;
	CvPlot* pTargetPlot = NULL;
	PlayerTypes eTargetPlayer = NO_PLAYER;
	int iExtraData = -1;
	
	eBestMission = GET_PLAYER(getOwnerINLINE()).AI_bestPlotEspionage(plot(), eTargetPlayer, pTargetPlot, iExtraData);
	if (NO_ESPIONAGEMISSION == eBestMission)
	{
		return false;
	}

	if (!GET_PLAYER(getOwnerINLINE()).canDoEspionageMission(eBestMission, eTargetPlayer, pTargetPlot, iExtraData, this))
	{
		return false;
	}
	
	if (!espionage(eBestMission, iExtraData))
	{
		return false;
	}
	
	return true;
}

bool CvUnitAI::AI_moveToStagingCity()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvCity* pBestCity = NULL;
	CvPlot* pBestPlot;

	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;

	iBestValue = 0;
	pBestPlot = NULL;
	
	int iWarCount = 0;
	TeamTypes eTargetTeam = NO_TEAM;
	CvTeam& kTeam = GET_TEAM(getTeam());
	for (int iI = 0; iI < MAX_TEAMS; iI++)
	{
		if ((iI != getTeam()) && GET_TEAM((TeamTypes)iI).isAlive())
		{
			if (kTeam.AI_isSneakAttackPreparing((TeamTypes)iI))
			{
				//OutputDebugString(CvString::format("AI_moveToStagingCity - potential target team %d\n", iI).c_str());
				eTargetTeam = (TeamTypes)iI;
				iWarCount++;
			}			
		}		
	}
	if (iWarCount > 1)
	{
		PROFILE("CvUnitAI::AI_moveToStagingCity.MultiTargetTeams");

		//OutputDebugString("AI_moveToStagingCity - no target team\n");
		eTargetTeam = NO_TEAM;
	}

	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	//	Do a rough pathing to arrange the cities into a heuristically optimal order so
	//	that the detailed pathing is most likely to get the best cities first, and hence generate lower
	//	cutoffs for max path on later ones (and hence execute faster)
	std::multimap<int,std::pair<CvCity*,int> > orderedTargets;
	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		PROFILE("AI_moveToStagingCity.Valuation");

		// BBAI efficiency: check same area
		if (pLoopCity->area() == area())
		{
			CvReachablePlotSet::const_iterator itr = plotSet.find(pLoopCity->plot());
			
			if ( itr != plotSet.end())
			{
				//	If we're not at war with anyone and we are not inside our own territory
				//	then we're just trying to return home - consider all cities equal
				if ( iWarCount == 0 && plot()->getOwnerINLINE() != getOwnerINLINE() )
				{
					iValue = 100;
				}
				else
				{
					// BBAI TODO: Need some knowledge of whether this is a good city to attack from ... only get that
					// indirectly from threat.
					iValue = pLoopCity->AI_cityThreat(eTargetTeam);
				}

				// Have attack stacks in assault areas move to coastal cities for faster loading
				if( (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT) || (area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT_MASSING) )
				{
					CvArea* pWaterArea = pLoopCity->waterArea();
					if( pWaterArea != NULL && GET_TEAM(getTeam()).AI_isWaterAreaRelevant(pWaterArea) )
					{
						// BBAI TODO:  Need a better way to determine which cities should serve as invasion launch locations

						// Inertia so units don't just chase transports around the map
						iValue = iValue/2;
						if( pLoopCity->area()->getAreaAIType(getTeam()) == AREAAI_ASSAULT )
						{
							// If in assault, transports may be at sea ... tend to stay where they left from
							// to speed reinforcement
							iValue += pLoopCity->plot()->plotCount(PUF_isAvailableUnitAITypeGroupie, UNITAI_ATTACK_CITY, -1, getOwnerINLINE());
						}

						// Attraction to cities which are serving as launch/pickup points
						iValue += 3*pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_ASSAULT_SEA, -1, getOwnerINLINE());
						iValue += 2*pLoopCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_ESCORT_SEA, -1, getOwnerINLINE());
						iValue += 5*GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_PICKUP);
					}
					else
					{
						iValue = iValue/8;
					}
				}

				if ((pLoopCity->plot() != plot()) && pLoopCity->isVisible(eTargetTeam, false))
				{
					iValue /= 2;
				}

				iValue *= 1000;

				//	Do a first-stage cut-off even on the rough paths to eliminate particualrly unlikely
				//	candidates.  The +4 in this calculation (lack of -4 relative to the vrsion in the final
				//	detailed evaluation) is to allow a little leeway since the optimal
				//	paths may vary somewhat from the rough ones.  The 2* is because the plotSet step distance
				//	is route-blind
				int iMaxTurns = (iBestValue == 0 ? MAX_INT : 2*iValue/iBestValue);

				//OutputDebugString(CvString::format("Generate rough path to (%d,%d) [value %d] with maxTurns=%d\n", pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), iValue, iMaxTurns).c_str());
				//if ( generatePath(pLoopCity->plot(), MOVE_IGNORE_DANGER | MOVE_THROUGH_ENEMY, true, &iPathTurns, iMaxTurns, 0) )
				if ( itr.stepDistance() <= iMaxTurns )
				{
					iPathTurns = itr.stepDistance();

					//OutputDebugString(CvString::format("\tSuccess.  PathTurns=%d\n", iPathTurns).c_str());
					int iPriority = iValue/(5 + iPathTurns);

					if (iPriority > iBestValue)
					{
						OutputDebugString(CvString::format("\tNew best value: %d\n", iPriority).c_str());
						iBestValue = iPriority;
					}

					int iDistance = iPathTurns;
					orderedTargets.insert(std::make_pair(iPriority,std::make_pair(pLoopCity,iValue)));
				}
				//else
				//{
				//	OutputDebugString("\tNot pathable\n");
				//}

				//OutputDebugString(CvString::format("City @(%d,%d), distance %d, value %d - add at priority %d\n",pLoopCity->getX_INLINE(),pLoopCity->getY_INLINE(),iDistance,iValue,iPriority).c_str());
			}
		}
	}

	iBestValue = 0;

	for(std::multimap<int,std::pair<CvCity*,int> >::const_iterator itr = orderedTargets.begin(); itr != orderedTargets.end(); ++itr)
	{
		pLoopCity = itr->second.first;
		iValue = itr->second.second;

		//	For barbarians we can assume they won't be using routes so we can make
		//	a decent estimate of their minimal possible path length
		int iMinPath;

		if ( getOwnerINLINE() == BARBARIAN_PLAYER )
		{
			iMinPath = std::max(1,stepDistance(m_iX, m_iY, pLoopCity->plot()->getX_INLINE(), pLoopCity->plot()->getY_INLINE())/baseMoves());
		}
		else
		{
			iMinPath = 1;
		}

		//OutputDebugString(CvString::format("City (%d,%d), value=%d, minPath=%d\n", pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE(), iValue).c_str());
		if (iValue/(5 + iMinPath) > iBestValue)
		{
			PROFILE("CvUnitAI::AI_moveToStagingCity.Pathing");

			int iMaxTurns = (iBestValue == 0 ? MAX_INT : iValue/iBestValue - 4);

			//OutputDebugString(CvString::format("Attempt pathing with maxPath=%d\n", iMaxTurns).c_str());
			if (generatePath(pLoopCity->plot(), MOVE_IGNORE_DANGER, true, &iPathTurns, iMaxTurns))
			{
				PROFILE("CvUnitAI::AI_moveToStagingCity.DangerCheck");
				OutputDebugString(CvString::format("Pathing suceeded with path len %d\n", iPathTurns).c_str());

				iValue /= (5 + iPathTurns);

				if (iValue > iBestValue)
				{
					CvPlot* endTurnPlot = getPathEndTurnPlot();

					if ( endTurnPlot == pLoopCity->plot() || !exposedToDanger(endTurnPlot, 60) )
					{
						iBestValue = iValue;
						pBestPlot = endTurnPlot;
						pBestCity = pLoopCity;
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		if (atPlot(pBestPlot))
		{
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
		else
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_GROUP, pBestCity->plot());
		}
	}

	return false;
}

/*
bool CvUnitAI::AI_seaRetreatFromCityDanger()
{
	if (plot()->isCity(true) && GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0) //prioritize getting outta there
	{
		if (AI_anyAttack(2, 40))
		{
			return true;
		}

		if (AI_anyAttack(4, 50))
		{
			return true;
		}

		if (AI_retreatToCity())
		{
			return true;
		}

		if (AI_safety())
		{
			return true;
		}
	}
	return false;
}

bool CvUnitAI::AI_airRetreatFromCityDanger()
{
	if (plot()->isCity(true))
	{
		CvCity* pCity = plot()->getPlotCity();
		if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(plot(), 2) > 0 || (pCity != NULL && !pCity->AI_isDefended()))
		{
			if (AI_airOffensiveCity())
			{
				return true;
			}

			if (canAirDefend() && AI_airDefensiveCity())
			{
				return true;
			}
		}
	}
	return false;
}

bool CvUnitAI::AI_airAttackDamagedSkip()
{
	if (getDamage() == 0)
	{
		return false;
	}

	bool bSkip = (currHitPoints() * 100 / maxHitPoints() < 40);
	if (!bSkip)
	{
		int iSearchRange = airRange();
		bool bSkiesClear = true;
		for (int iDX = -iSearchRange; iDX <= iSearchRange && bSkiesClear; iDX++)
		{
			for (int iDY = -iSearchRange; iDY <= iSearchRange && bSkiesClear; iDY++)
			{
				CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);	
				if (pLoopPlot != NULL)
				{
					if (bestInterceptor(pLoopPlot) != NULL)
					{
						bSkiesClear = false;
						break;
					}
				}
			}
		}
		bSkip = !bSkiesClear;
	}

	if (bSkip)
	{
		getGroup()->pushMission(MISSION_SKIP);
		return true;
	}

	return false;
}
*/

// Returns true if a mission was pushed or we should wait for another unit to bombard...
bool CvUnitAI::AI_followBombard()
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pAdjacentPlot1;
	CvPlot* pAdjacentPlot2;
	int iI, iJ;
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/

	if(getGroup()->canBombard(plot())) 
	{
		// RevolutionDCM - ranged bombard AI wraps standard bombard
		if (!AI_RbombardCity(bombardTarget(plot())))
		{
			// vanilla behaviour
			getGroup()->pushMission(MISSION_BOMBARD);
			return true;
		}
		// RevolutionDCM - end
	}
/************************************************************************************************/
/* REVOLUTIONDCM                            END                                     Glider1     */
/************************************************************************************************/
	if (getDomainType() == DOMAIN_LAND)
	{
		for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
		{
			pAdjacentPlot1 = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));

			if (pAdjacentPlot1 != NULL)
			{
				if (pAdjacentPlot1->isCity())
				{
					if (AI_potentialEnemy(pAdjacentPlot1->getTeam(), pAdjacentPlot1))
					{
						for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
						{
							pAdjacentPlot2 = plotDirection(pAdjacentPlot1->getX_INLINE(), pAdjacentPlot1->getY_INLINE(), ((DirectionTypes)iJ));

							if (pAdjacentPlot2 != NULL)
							{
								pUnitNode = pAdjacentPlot2->headUnitNode();

								while (pUnitNode != NULL)
								{
									pLoopUnit = ::getUnit(pUnitNode->m_data);
									pUnitNode = pAdjacentPlot2->nextUnitNode(pUnitNode);

									if (pLoopUnit->getOwnerINLINE() == getOwnerINLINE())
									{
										if (pLoopUnit->canBombard(pAdjacentPlot2))
										{
											if (pLoopUnit->isGroupHead())
											{
												if (pLoopUnit->getGroup() != getGroup())
												{
													if (pLoopUnit->getGroup()->readyToMove())
													{
														return true;
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	return false;
}


// Returns true if the unit has found a potential enemy...
bool CvUnitAI::AI_potentialEnemy(TeamTypes eTeam, const CvPlot* pPlot)
{
	PROFILE_FUNC();

	if (getGroup()->AI_isDeclareWar(pPlot))
	{
		return isPotentialEnemy(eTeam, pPlot);
	}
	else
	{
		return isEnemy(eTeam, pPlot);
	}
}


// Returns true if this plot needs some defense...
bool CvUnitAI::AI_defendPlot(CvPlot* pPlot)
{
	CvCity* pCity;

	if (!canDefend(pPlot))
	{
		return false;
	}

	bool	bHasTerrainDamage = (plot()->getTerrainTurnDamage(getGroup()) > 0 ||
									(plot()->getFeatureTurnDamage() > 0));	
	
	pCity = pPlot->getPlotCity();

	if (bHasTerrainDamage && !pPlot->isRoute() && pCity == NULL) 
	{
		return false;
	}

	if (pCity != NULL)
	{
		if (pCity->getOwnerINLINE() == getOwnerINLINE())
		{
			if (pCity->AI_isDanger())
			{
				return true;
			}
		}
	}
	else
	{
		if (pPlot->plotCount(PUF_canDefendGroupHead, -1, -1, getOwnerINLINE()) <= ((atPlot(pPlot)) ? 1 : 0))
		{
			if (pPlot->plotCount(PUF_cannotDefend, -1, -1, getOwnerINLINE()) > 0)
			{
				return true;
			}

//			if (pPlot->defenseModifier(getTeam(), false) >= 50 && pPlot->isRoute() && pPlot->getTeam() == getTeam())
//			{
//				return true;
//			}
		}
	}

	return false;
}


int CvUnitAI::AI_pillageValue(CvPlot* pPlot, int iBonusValueThreshold)
{
	CvPlot* pAdjacentPlot;
	ImprovementTypes eImprovement;
	BonusTypes eNonObsoleteBonus;
	int iValue;
	int iTempValue;
	int iBonusValue;
	int iI;

	FAssert(getGroup()->canPillage(pPlot) || canAirBombAt(plot(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) || (getGroup()->getCargo() > 0));

	if (!(pPlot->isOwned()))
	{
		return 0;
	}
	
	iBonusValue = 0;
	eNonObsoleteBonus = pPlot->getNonObsoleteBonusType(pPlot->getTeam());
	if (eNonObsoleteBonus != NO_BONUS)
	{
		iBonusValue = (GET_PLAYER(pPlot->getOwnerINLINE()).AI_bonusVal(eNonObsoleteBonus));
	}
	
	if (iBonusValueThreshold > 0)
	{
		if (eNonObsoleteBonus == NO_BONUS)
		{
			return 0;
		}
		else if (iBonusValue < iBonusValueThreshold)
		{
			return 0;
		}
	}

	iValue = 0;
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	// RevolutionDCM - ranged bombardment plot
	// Dale - RB: Field Bombard START
	//if (getDomainType() != DOMAIN_AIR && getDCMBombRange() < 1)
	// Dale - RB: Field Bombard END
/************************************************************************************************/
/* REVOLUTIONDCM                            END	                                 Glider1     */
/************************************************************************************************/
	{
		if (pPlot->isRoute())
		{
			iValue++;
			if (eNonObsoleteBonus != NO_BONUS)
			{
				iValue += iBonusValue * 4;
			}

			for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));

				if (pAdjacentPlot != NULL && pAdjacentPlot->getTeam() == pPlot->getTeam())
				{
					if (pAdjacentPlot->isCity())
					{
						iValue += 10;
					}

					if (!(pAdjacentPlot->isRoute()))
					{
					
/************************************************************************************************/
/* Afforess	                  Start		 08/02/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
/*
						if (!(pAdjacentPlot->isWater()) && !(pAdjacentPlot->isImpassable()))
*/
						if (!(pAdjacentPlot->isWater()) && !(pAdjacentPlot->isImpassable(getTeam())))
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
						{
							iValue += 2;
						}
					}
				}
			}
		}
	}

	if (pPlot->getImprovementDuration() > ((pPlot->isWater()) ? 20 : 5))
	{
		eImprovement = pPlot->getImprovementType();
	}
	else
	{
		eImprovement = pPlot->getRevealedImprovementType(getTeam(), false);
	}

	if (eImprovement != NO_IMPROVEMENT)
	{
		if (pPlot->getWorkingCity() != NULL)
		{
			iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_FOOD, pPlot->getOwnerINLINE()) * 5);
			iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_PRODUCTION, pPlot->getOwnerINLINE()) * 4);
			iValue += (pPlot->calculateImprovementYieldChange(eImprovement, YIELD_COMMERCE, pPlot->getOwnerINLINE()) * 3);
		}
/************************************************************************************************/
/* REVOLUTIONDCM                            05/24/08                                Glider1     */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		// RevolutionDCM - ranged bombardment plot
		// Dale - RB: Field Bombard START
		//if (getDomainType() != DOMAIN_AIR && getDCMBombRange() < 1)
		// Dale - RB: Field Bombard END
/************************************************************************************************/
/* REVOLUTIONDCM                            END                                     Glider1     */
/************************************************************************************************/
		{
			iValue += GC.getImprovementInfo(eImprovement).getPillageGold();
		}

		if (eNonObsoleteBonus != NO_BONUS)
		{
			if (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eNonObsoleteBonus))
			{
				iTempValue = iBonusValue * 4;

				if (pPlot->isConnectedToCapital() && (pPlot->getPlotGroupConnectedBonus(pPlot->getOwnerINLINE(), eNonObsoleteBonus) == 1))
				{
					iTempValue *= 2;
				}

				iValue += iTempValue;
			}
		}
	}

	return iValue;
}

int CvUnitAI::AI_nukeValue(CvCity* pCity)
{
	PROFILE_FUNC();
	FAssertMsg(pCity != NULL, "City is not assigned a valid value");

	for (int iI = 0; iI < MAX_TEAMS; iI++)
	{
		CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iI);
		if (kLoopTeam.isAlive() && !isEnemy((TeamTypes)iI))
		{
			if (isNukeVictim(pCity->plot(), ((TeamTypes)iI)))
			{
				// Don't start wars with neutrals
				return 0;
			}
		}
	}

	int iValue = 1;

	iValue += GC.getGameINLINE().getSorenRandNum((pCity->getPopulation() + 1), "AI Nuke City Value");
	iValue += std::max(0, pCity->getPopulation() - 10);

	iValue += ((pCity->getPopulation() * (100 + pCity->calculateCulturePercent(pCity->getOwnerINLINE()))) / 100);

	iValue += -(GET_PLAYER(getOwnerINLINE()).AI_getAttitudeVal(pCity->getOwnerINLINE()) / 3);

	for (int iDX = -(nukeRange()); iDX <= nukeRange(); iDX++)
	{
		for (int iDY = -(nukeRange()); iDY <= nukeRange(); iDY++)
		{
			CvPlot* pLoopPlot = plotXY(pCity->getX_INLINE(), pCity->getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT)
				{
					iValue++;
				}

				/********************************************************************************/
				/* 	BETTER_BTS_AI_MOD						7/31/08				jdog5000	*/
				/* 																			*/
				/* 	Bugfix																	*/
				/********************************************************************************/
				//if (pLoopPlot->getBonusType() != NO_BONUS)
				if (pLoopPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
				{
					iValue++;
				}
				/********************************************************************************/
				/* 	BETTER_BTS_AI_MOD						END								*/
				/********************************************************************************/
			}
		}
	}
	
	if (!(pCity->isEverOwned(getOwnerINLINE())))
	{
		iValue *= 3;
		iValue /= 2;
	}
	
	if (!GET_TEAM(pCity->getTeam()).isAVassal())
	{
		iValue *= 2;
	}
	
	if (pCity->plot()->isVisible(getTeam(), false))
	{
		iValue += 2 * pCity->plot()->getNumVisibleEnemyDefenders(this);
	}
	else
	{
		iValue += 6;
	}

	return iValue;
}


int CvUnitAI::AI_searchRange(int iRange)
{
	if (iRange == 0)
	{
		return 0;
	}
	else if ( iRange == MAX_INT )
	{
		return MAX_SEARCH_RANGE;
	}

	if (flatMovementCost() || (getDomainType() == DOMAIN_SEA))
	{
		return std::min(MAX_SEARCH_RANGE,iRange * baseMoves());
	}
	else
	{
		return std::min(MAX_SEARCH_RANGE,(iRange + 1) * (baseMoves() + 1));
	}
}


// XXX at some point test the game with and without this function...
bool CvUnitAI::AI_plotValid(CvPlot* pPlot) const
{
	PROFILE_FUNC();

	if (m_pUnitInfo->isNoRevealMap() && willRevealByMove(pPlot))
	{
		return false;
	}

	switch (getDomainType())
	{
	case DOMAIN_SEA:
/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 07/07/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		if (pPlot->isWater() || canMoveAllTerrain() || pPlot->isCanMoveSeaUnits())
		{
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
			return true;
		}
		else if (pPlot->isFriendlyCity(*this, true) && pPlot->isCoastalLand())
		{
			return true;
		}
		break;

	case DOMAIN_AIR:
		FAssert(false);
		break;

	case DOMAIN_LAND:
/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 07/07/09                                                        */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
		if (!pPlot->isWater() || canMoveAllTerrain() || pPlot->isCanMoveLandUnits())
/************************************************************************************************/
/* JOOYO_ADDON                          END                                                     */
/************************************************************************************************/
		{
			return true;
		}
		break;

	case DOMAIN_IMMOBILE:
		break;

	default:
		FAssert(false);
		break;
	}

	return false;
}


int CvUnitAI::AI_finalOddsThreshold(CvPlot* pPlot, int iOddsThreshold)
{
	PROFILE_FUNC();

	CvCity* pCity;

	int iFinalOddsThreshold;

	iFinalOddsThreshold = iOddsThreshold;

	pCity = pPlot->getPlotCity();

	if (pCity != NULL)
	{
		if (pCity->getDefenseDamage() < ((GC.getMAX_CITY_DEFENSE_DAMAGE() * 3) / 4))
		{
			iFinalOddsThreshold += std::max(0, (pCity->getDefenseDamage() - pCity->getLastDefenseDamage() - (GC.getDefineINT("CITY_DEFENSE_DAMAGE_HEAL_RATE") * 2)));
		}
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/29/10                                jdog5000      */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
/* original bts code
	if (pPlot->getNumVisiblePotentialEnemyDefenders(this) == 1)
	{
		if (pCity != NULL)
		{
			iFinalOddsThreshold *= 2;
			iFinalOddsThreshold /= 3;
		}
		else
		{
			iFinalOddsThreshold *= 7;
			iFinalOddsThreshold /= 8;
		}
	}

	if ((getDomainType() == DOMAIN_SEA) && !getGroup()->hasCargo())
	{
		iFinalOddsThreshold *= 3;
		iFinalOddsThreshold /= 2 + getGroup()->getNumUnits();
	}
	else
	{
		iFinalOddsThreshold *= 6;
		iFinalOddsThreshold /= (3 + GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pPlot, true) + ((stepDistance(getX_INLINE(), getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) > 1) ? 1 : 0) + ((AI_isCityAIType()) ? 2 : 0));
	}
*/
	int iDefenders = pPlot->getNumVisiblePotentialEnemyDefenders(this);

	// More aggressive if only one enemy defending city
	if (iDefenders == 1 && pCity != NULL)
	{
		iFinalOddsThreshold *= 2;
		iFinalOddsThreshold /= 3;
	}

#ifdef __OLD_METHOD_PRE_ACCURATE_STACK_CALCULATIONS
/************************************************************************************************/
/* Afforess	                  Start		 09/20/10                                               */
/*                                                                                              */
/*                                                                                              */
/************************************************************************************************/
	if (iDefenders * 2 < getGroup()->getNumUnits() * 3)
	{
		if (getGroup()->getAutomateType() == AUTOMATE_HUNT)
		{
			if (GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_HUNT_ALLOW_UNIT_SUICIDING))
			{
				int iInitialOddsThreshold = iFinalOddsThreshold;
				iFinalOddsThreshold /= getGroup()->getNumUnits();
				iFinalOddsThreshold *= 2;
				iFinalOddsThreshold = std::min(iInitialOddsThreshold, iFinalOddsThreshold);
			}
		}
		else if (getGroup()->getAutomateType() == AUTOMATE_BORDER_PATROL)
		{
			if (GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PATROL_ALLOW_UNIT_SUICIDING))
			{
				int iInitialOddsThreshold = iFinalOddsThreshold;
				iFinalOddsThreshold /= getGroup()->getNumUnits();
				iFinalOddsThreshold *= 2;
				iFinalOddsThreshold = std::min(iInitialOddsThreshold, iFinalOddsThreshold);
			}
		}
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	if ((getDomainType() == DOMAIN_SEA) && !getGroup()->hasCargo())
	{
		iFinalOddsThreshold *= 3 + (iDefenders/2);
		iFinalOddsThreshold /= 2 + getGroup()->getNumUnits();
	}
	else
	{
		iFinalOddsThreshold *= 6 + (iDefenders/((pCity != NULL) ? 1 : 2));
		int iDivisor = 3;
		iDivisor += GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pPlot, true);
		iDivisor += ((stepDistance(getX_INLINE(), getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) > 1) ? getGroup()->getNumUnits() : 0);
		iDivisor += (AI_isCityAIType() ? 2 : 0);
		iFinalOddsThreshold /= iDivisor;
	}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
#else
	if ((getDomainType() == DOMAIN_SEA) && getGroup()->hasCargo())
	{
		iFinalOddsThreshold = (iFinalOddsThreshold*3)/2;	// don't risk cargo without better odds
	}
	else
	{
		iFinalOddsThreshold *= 6;
		int iDivisor = 5;
		//	Koshling - old code to adjust odds for potential extra attacketrs is redundant now that base
		//	odds calculate using stack odds
		//int iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pPlot, true);
		//iDivisor += iPotentialAttackers;
		iDivisor += (AI_isCityAIType() ? 2 : 0);
		iDivisor += ((AI_getUnitAIType() == UNITAI_ATTACK_CITY || AI_getUnitAIType() == UNITAI_ATTACK) ? 2 : 0);
		iFinalOddsThreshold /= iDivisor;
	}
#endif

	return range(iFinalOddsThreshold, 1, 99);
}


int CvUnitAI::AI_stackOfDoomExtra()
{
	return ((AI_getBirthmark() % (1 + GET_PLAYER(getOwnerINLINE()).getCurrentEra())) + 4);
}

bool CvUnitAI::AI_stackAttackCity(int iRange, int iPowerThreshold, bool bFollow)
{
    PROFILE_FUNC();
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	FAssert(canMove());

	if (bFollow)
	{
		iSearchRange = 1;
	}
	else
	{
		iSearchRange = AI_searchRange(iRange);
	}

	iBestValue = 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot))
				{
					if (pLoopPlot->isCity() || (pLoopPlot->isCity(true) && pLoopPlot->isVisibleEnemyUnit(this)))
					{
						if (AI_potentialEnemy(pLoopPlot->getTeam(), pLoopPlot))
						{
							//	Allow for empty cities (so the move in is strictly not an attack)
							if (!atPlot(pLoopPlot) && ((bFollow) ? (getGroup()->canMoveInto(pLoopPlot, true) || getGroup()->canMoveInto(pLoopPlot, false)) : (generatePath(pLoopPlot, 0, true, &iPathTurns, iRange) && (iPathTurns <= iRange))))
							{
								iValue = getGroup()->AI_compareStacks(pLoopPlot, /*bPotentialEnemy*/ true, /*bCheckCanAttack*/ true, /*bCheckCanMove*/ true);

								if (iValue >= iPowerThreshold)
								{
									if (iValue > iBestValue)
									{
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( bFollow || endTurnPlot == pLoopPlot || !exposedToDanger((bFollow) ? pLoopPlot : endTurnPlot, 60) )
										{
											iBestValue = iValue;
											pBestPlot = ((bFollow) ? pLoopPlot : endTurnPlot);
											FAssert(!atPlot(pBestPlot));
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/05/10                                jdog5000      */
/*                                                                                              */
/* AI logging                                                                                   */
/************************************************************************************************/
		if( gUnitLogLevel >= 1 && pBestPlot->getPlotCity() != NULL )
		{
			logBBAI("    Stack for player %d (%S) decides to attack city %S with stack ratio %d", getOwner(), GET_PLAYER(getOwner()).getCivilizationDescription(0), pBestPlot->getPlotCity()->getName(0).GetCString(), iBestValue );
			logBBAI("    City %S has defense modifier %d, %d with ignore building", pBestPlot->getPlotCity()->getName(0).GetCString(), pBestPlot->getPlotCity()->getDefenseModifier(false), pBestPlot->getPlotCity()->getDefenseModifier(true) );
		}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), ((bFollow) ? MOVE_DIRECT_ATTACK : 0));
	}

	return false;
}

bool CvUnitAI::AI_moveIntoCity(int iRange)
{
    PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange = iRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	FAssert(canMove());

	iBestValue = 0;
	pBestPlot = NULL;
	
	if (plot()->isCity())
	{
	    return false;
	}

	iSearchRange = AI_searchRange(iRange);

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
			
			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot) && (!isEnemy(pLoopPlot->getTeam(), pLoopPlot)))
				{
					if (pLoopPlot->isCity() || (pLoopPlot->isCity(true)))
					{
                        if (canMoveInto(pLoopPlot, false) && (generatePath(pLoopPlot, 0, true, &iPathTurns, 0)))
                        {
							FAssert(getPathEndTurnPlot() == pLoopPlot);

                            iValue = 1;
                            if (pLoopPlot->getPlotCity() != NULL)
                            {
                                 iValue += pLoopPlot->getPlotCity()->getPopulation();                                
                            }
                            
                            if (iValue > iBestValue)
                            {
                                iBestValue = iValue;
                                pBestPlot = getPathEndTurnPlot();
                                FAssert(!atPlot(pBestPlot));
                            }
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}

//bolsters the culture of the weakest city.
//returns true if a mission is pushed.
bool CvUnitAI::AI_artistCultureVictoryMove()
{
    bool bGreatWork = false;
    bool bJoin = true;

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/08/10                                jdog5000      */
/*                                                                                              */
/* Victory Strategy AI                                                                          */
/************************************************************************************************/
    if (!(GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE1)))
    {
        return false;        
    }
    
    if (GET_PLAYER(getOwnerINLINE()).AI_isDoVictoryStrategy(AI_VICTORY_CULTURE3))
    {
        //Great Work
        bGreatWork = true;
    }
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

	int iCultureCitiesNeeded = GC.getGameINLINE().culturalVictoryNumCultureCities();
	FAssertMsg(iCultureCitiesNeeded > 0, "CultureVictory Strategy should not be true");

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvCity* pBestCity;
	SpecialistTypes eBestSpecialist;
	int iLoop, iValue, iBestValue;

	pBestPlot = NULL;
	eBestSpecialist = NO_SPECIALIST;

	pBestCity = NULL;
	
	iBestValue = 0;
	iLoop = 0;
	
	int iTargetCultureRank = iCultureCitiesNeeded;
	while (iTargetCultureRank > 0 && pBestCity == NULL)
	{
		for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
		{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/19/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
			// BBAI efficiency: check same area
			if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
			{
				// instead of commerce rate rank should use the culture on tile...
				if (pLoopCity->findCommerceRateRank(COMMERCE_CULTURE) == iTargetCultureRank)
				{
					// if the city is a fledgling, probably building culture, try next higher city
					if (pLoopCity->getCultureLevel() < 2)
					{
						break;
					}
					
					// if we cannot path there, try the next higher culture city
					if (!generatePath(pLoopCity->plot(), 0, true))
					{
						break;
					}

					pBestCity = pLoopCity;
					pBestPlot = pLoopCity->plot();
					if (bGreatWork)
					{
						if (canGreatWork(pBestPlot))
						{
							break;
						}
					}

					for (int iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
					{
						if (canJoin(pBestPlot, ((SpecialistTypes)iI)))
						{
							iValue = pLoopCity->AI_specialistValue(((SpecialistTypes)iI), pLoopCity->AI_avoidGrowth(), false);

							if (iValue > iBestValue)
							{
								iBestValue = iValue;
								eBestSpecialist = ((SpecialistTypes)iI);
							}
						}
					}

					if (eBestSpecialist == NO_SPECIALIST)
					{
						bJoin = false;
						if (canGreatWork(pBestPlot))
						{
							bGreatWork = true; 
							break;                        
						}
						bGreatWork = false;
					}
					break;
				}
			}
		}
	
		iTargetCultureRank--;
	}


	FAssertMsg(bGreatWork || bJoin, "This wasn't a Great Artist");
	
	if (pBestCity == NULL)
	{
	    //should try to airlift there...
	    return false;
	}


    if (atPlot(pBestPlot))
    {
        if (bGreatWork)
        {
            getGroup()->pushMission(MISSION_GREAT_WORK);
            return true;
        }
        if (bJoin)
        {
            getGroup()->pushMission(MISSION_JOIN, eBestSpecialist);
            return true;
        }
        FAssert(false);
        return false;		    
    }
    else
    {
        FAssert(!atPlot(pBestPlot));
        return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
    }
}    

bool CvUnitAI::AI_poach()
{
	CvPlot* pLoopPlot;
	int iX, iY;
	
	int iBestPoachValue = 0;
	CvPlot* pBestPoachPlot = NULL;
	TeamTypes eBestPoachTeam = NO_TEAM;
	
	if (!GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
	{
		return false;
	}
	
	if (GET_TEAM(getTeam()).getNumMembers() > 1)
	{
		return false;
	}
	
	int iNoPoachRoll = GET_PLAYER(getOwnerINLINE()).AI_totalUnitAIs(UNITAI_WORKER);
	iNoPoachRoll += GET_PLAYER(getOwnerINLINE()).getNumCities();
	iNoPoachRoll = std::max(0, (iNoPoachRoll - 1) / 2);
	if (GC.getGameINLINE().getSorenRandNum(iNoPoachRoll, "AI Poach") > 0)
	{
		return false;
	}

	if (GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0)
	{
		return false;
	}
	
	FAssert(canAttack());
	
	
	
	int iRange = 1;
	//Look for a unit which is non-combat
	//and has a capture unit type
	for (iX = -iRange; iX <= iRange; iX++)
	{
		for (iY = -iRange; iY <= iRange; iY++)
		{
			if (iX != 0 && iY != 0)
			{
				pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
				if ((pLoopPlot != NULL) && (pLoopPlot->getTeam() != getTeam()) && pLoopPlot->isVisible(getTeam(), false))
				{
					int iPoachCount = 0;
					int iDefenderCount = 0;
					CvUnit* pPoachUnit = NULL;
					CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
					while (pUnitNode != NULL)
					{
						CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
						pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
						if ((pLoopUnit->getTeam() != getTeam())
							&& GET_TEAM(getTeam()).canDeclareWar(pLoopUnit->getTeam()))
						{
							if (!pLoopUnit->canDefend())
							{
								if (pLoopUnit->getCaptureUnitType(getCivilizationType()) != NO_UNIT)
								{
									iPoachCount++;
									pPoachUnit = pLoopUnit;						
								}
							}
							else
							{
								iDefenderCount++;
							}
						}
					}
					
					if (pPoachUnit != NULL)
					{
						if (iDefenderCount == 0)
						{
							int iValue = iPoachCount * 100;
							iValue -= iNoPoachRoll * 25;
							if (iValue > iBestPoachValue)
							{
								iBestPoachValue = iValue;
								pBestPoachPlot = pLoopPlot;
								eBestPoachTeam = pPoachUnit->getTeam();
							}
						}
					}
				}
			}
		}
	}
	
	if (pBestPoachPlot != NULL)
	{
		//No war roll.
		if (!GET_TEAM(getTeam()).AI_performNoWarRolls(eBestPoachTeam))
		{
			GET_TEAM(getTeam()).declareWar(eBestPoachTeam, true, WARPLAN_LIMITED);
			
			FAssert(!atPlot(pBestPoachPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPoachPlot->getX_INLINE(), pBestPoachPlot->getY_INLINE(), MOVE_DIRECT_ATTACK);
		}
		
	}
	
	return false;
}

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/31/10                                jdog5000      */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
bool CvUnitAI::AI_choke(int iRange, bool bDefensive)
{
	PROFILE_FUNC();

	bool bNoDefensiveBonus = noDefensiveBonus();
	if( getGroup()->getNumUnits() > 1 )
	{
		CLLNode<IDInfo>* pUnitNode = getGroup()->headUnitNode();
		CvUnit* pLoopUnit = NULL;

		while( pUnitNode != NULL )
		{
			pLoopUnit = ::getUnit(pUnitNode->m_data);
			bNoDefensiveBonus = (bNoDefensiveBonus && pLoopUnit->noDefensiveBonus());

			pUnitNode = getGroup()->nextUnitNode(pUnitNode);
		}
	}

	CvPlot* pBestPlot = NULL;
	int iBestValue = 0;
	for (int iX = -iRange; iX <= iRange; iX++)
	{
		for (int iY = -iRange; iY <= iRange; iY++)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iX, iY);
			if (pLoopPlot != NULL)
			{
				if (isEnemy(pLoopPlot->getTeam()) && (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this)))
				{
					CvCity* pWorkingCity = pLoopPlot->getWorkingCity();
					if ((pWorkingCity != NULL) && (pWorkingCity->getTeam() == pLoopPlot->getTeam()))
					{
						bool	bHasTerrainDamage = (plot()->getTerrainTurnDamage(getGroup()) > 0 ||
								(plot()->getFeatureTurnDamage() > 0));	

						if(!bHasTerrainDamage)
						{
							int iValue = (bDefensive ? pLoopPlot->defenseModifier(getTeam(), false) : -15);
							if (pLoopPlot->getBonusType(getTeam()) != NO_BONUS)
							{
								iValue += GET_PLAYER(pLoopPlot->getOwnerINLINE()).AI_bonusVal(pLoopPlot->getBonusType(), 0);
							}
							
							iValue += pLoopPlot->getYield(YIELD_PRODUCTION) * 10;
							iValue += pLoopPlot->getYield(YIELD_FOOD) * 10;
							iValue += pLoopPlot->getYield(YIELD_COMMERCE) * 5;
							
							if (bNoDefensiveBonus)
							{
								iValue *= std::max(0, ((baseCombatStr() * 120) - GC.getGame().getBestLandUnitCombat()));
							}
							else
							{
								iValue *= pLoopPlot->defenseModifier(getTeam(), false);
							}
							
							if (iValue > 0)
							{
								if( !bDefensive )
								{
									iValue *= 10;
									iValue /= std::max(1, (pLoopPlot->getNumDefenders(getOwnerINLINE()) + ((pLoopPlot == plot()) ? 0 : getGroup()->getNumUnits())));
								}
								if (generatePath(pLoopPlot, 0, true, NULL, iRange))
								{
									CvPlot* endTurnPlot = getPathEndTurnPlot();

									if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 60) )
									{
										pBestPlot = endTurnPlot;
										iBestValue = iValue;
									}
								}
							}
						}
					}
				}
			}
		}
	}
	if (pBestPlot != NULL)
	{
		if (atPlot(pBestPlot))
		{
			if(getGroup()->canPillage(plot())) getGroup()->pushMission(MISSION_PILLAGE);
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
		else
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX(), pBestPlot->getY());
		}
	}
	
	return false;
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

bool CvUnitAI::AI_solveBlockageProblem(CvPlot* pDestPlot, bool bDeclareWar)
{
	PROFILE_FUNC();

	FAssert(pDestPlot != NULL);
	

	if (pDestPlot != NULL)
	{
		FAStarNode* pStepNode;
		
		CvPlot* pSourcePlot = plot();

		if (gDLL->getFAStarIFace()->GeneratePath(&GC.getStepFinder(), pSourcePlot->getX_INLINE(), pSourcePlot->getY_INLINE(), pDestPlot->getX_INLINE(), pDestPlot->getY_INLINE(), false, -1, true))
		{
			pStepNode = gDLL->getFAStarIFace()->GetLastNode(&GC.getStepFinder());

			while (pStepNode != NULL)
			{
				int iPathTurns;
				CvPlot* pStepPlot = GC.getMapINLINE().plotSorenINLINE(pStepNode->m_iX, pStepNode->m_iY);
				if (canMoveOrAttackInto(pStepPlot) && generatePath(pStepPlot, 0, false, &iPathTurns))
				{
					if (bDeclareWar && pStepNode->m_pPrev != NULL)
					{
						CvPlot* pPlot = GC.getMapINLINE().plotSorenINLINE(pStepNode->m_pPrev->m_iX, pStepNode->m_pPrev->m_iY);
						if (pPlot->getTeam() != NO_TEAM)
						{
							if (!getGroup()->canMoveIntoWithWar(pPlot, true, true))
							{
								if (!isPotentialEnemy(pPlot->getTeam(), pPlot))
								{									
									CvTeamAI& kTeam = GET_TEAM(getTeam());
									if (kTeam.canDeclareWar(pPlot->getTeam()))
									{
										WarPlanTypes eWarPlan = WARPLAN_LIMITED;
										WarPlanTypes eExistingWarPlan = kTeam.AI_getWarPlan(pDestPlot->getTeam());
										if (eExistingWarPlan != NO_WARPLAN)
										{
											if ((eExistingWarPlan == WARPLAN_TOTAL) || (eExistingWarPlan == WARPLAN_PREPARING_TOTAL))
											{
												eWarPlan = WARPLAN_TOTAL;
											}
											
											if (!kTeam.isAtWar(pDestPlot->getTeam()))
											{
												kTeam.AI_setWarPlan(pDestPlot->getTeam(), NO_WARPLAN);
											}
										}
										kTeam.AI_setWarPlan(pPlot->getTeam(), eWarPlan, true);
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      03/29/10                                jdog5000      */
/*                                                                                              */
/* War tactics AI                                                                               */
/************************************************************************************************/
/* original bts code
										return (AI_targetCity());
*/
										return (AI_goToTargetCity(MOVE_AVOID_ENEMY_WEIGHT_2));
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
										
									}
								}
							}
						}
					}
					if (pStepPlot->isVisible(getTeam(),false) && pStepPlot->isVisibleEnemyUnit(this))
					{
						FAssert(canAttack());
						CvPlot* pBestPlot = pStepPlot;
						//To prevent puppeteering attempt to barge through
						//if quite close
						if (iPathTurns > 3)
						{
							pBestPlot = getPathEndTurnPlot();
						}

						FAssert(!atPlot(pBestPlot));
						return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_DIRECT_ATTACK);
					}
				}
				pStepNode = pStepNode->m_pParent;
			}
		}
	}
	
	return false;
}

int CvUnitAI::AI_calculatePlotWorkersNeeded(CvPlot* pPlot, BuildTypes eBuild)
{
	int iBuildTime = pPlot->getBuildTime(eBuild) - pPlot->getBuildProgress(eBuild);
	int iWorkRate = workRate(true);
	
	if (iWorkRate <= 0)
	{
		FAssert(false);
		return 1;
	}
	int iTurns = iBuildTime / iWorkRate;
	
	if (iBuildTime > (iTurns * iWorkRate))
	{
		iTurns++;
	}
	
	int iNeeded = std::max(1, (iTurns + 2) / 3);
	
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						7/31/08				jdog5000	*/
	/* 																			*/
	/* 	Bugfix																	*/
	/********************************************************************************/
	//if (pPlot->getBonusType() != NO_BONUS)
	if (pPlot->getNonObsoleteBonusType(getTeam()) != NO_BONUS)
	{
		iNeeded *= 2;		
	}
	/********************************************************************************/
	/* 	BETTER_BTS_AI_MOD						END								*/
	/********************************************************************************/

	return iNeeded;
	
}

bool CvUnitAI::AI_canGroupWithAIType(UnitAITypes eUnitAI) const
{
	if (eUnitAI != AI_getUnitAIType())
	{
		switch (eUnitAI)
		{
		case (UNITAI_ATTACK_CITY):
			if (plot()->isCity() && (GC.getGame().getGameTurn() - plot()->getPlotCity()->getGameTurnAcquired()) <= 1)
			{
				return false;
			}
			break;
		default:
			break;
		}
	}

	return true;
}



bool CvUnitAI::AI_allowGroup(const CvUnit* pUnit, UnitAITypes eUnitAI) const
{
	CvSelectionGroup* pGroup = pUnit->getGroup();
	CvPlot* pPlot = pUnit->plot();

	if (pUnit == this)
	{
		return false;
	}

	//Don't let the AI regroup when we are gaurding a resource
	if (m_bClaimedTerritory)
	{
		return false;
	}

	if (!pUnit->isGroupHead())
	{
		return false;
	}

	//	Don't join a unit that was itself wondering what to do this turn
	if ( (static_cast<const CvUnitAI*>(pUnit))->m_contractsLastEstablishedTurn == GC.getGameINLINE().getGameTurn() &&
		 (m_contractualState == CONTRACTUAL_STATE_AWAITING_WORK || m_contractualState == CONTRACTUAL_STATE_NO_WORK_FOUND))
	{
		return false;
	}

	if (pGroup == getGroup())
	{
		return false;
	}

	if (pUnit->isCargo())
	{
		return false;
	}

	if (pUnit->AI_getUnitAIType() != eUnitAI)
	{
		return false;
	}

	switch (pGroup->AI_getMissionAIType())
	{
	case MISSIONAI_GUARD_CITY:
		// do not join groups that are guarding cities
		// intentional fallthrough
	case MISSIONAI_LOAD_SETTLER:
	case MISSIONAI_LOAD_ASSAULT:
	case MISSIONAI_LOAD_SPECIAL:
		// do not join groups that are loading into transports (we might not fit and get stuck in loop forever)
		return false;
		break;
	default:
		break;
	}

	if (pGroup->getActivityType() == ACTIVITY_HEAL)
	{
		// do not attempt to join groups which are healing this turn
		// (healing is cleared every turn for automated groups, so we know we pushed a heal this turn)
		return false;
	}

	if (!canJoinGroup(pPlot, pGroup))
	{
		return false;
	}

	if (eUnitAI == UNITAI_SETTLE)
	{
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      08/20/09                                jdog5000      */
/*                                                                                              */
/* Unit AI, Efficiency                                                                          */
/************************************************************************************************/
		//if (GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pPlot, 3) > 0)
		if (GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pPlot, 3))
		{
			return false;
		}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/
	}
	else if (eUnitAI == UNITAI_ASSAULT_SEA)
	{
		if (!pGroup->hasCargo())
		{
			return false;
		}
	}

	if ((getGroup()->getHeadUnitAI() == UNITAI_CITY_DEFENSE))
	{
		if (plot()->isCity() && (plot()->getTeam() == getTeam()) && plot()->getBestDefender(getOwnerINLINE())->getGroup() == getGroup())
		{
			return false;
		}
	}

	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		CvPlot* pTargetPlot = pGroup->AI_getMissionAIPlot();

		if (pTargetPlot != NULL)
		{
			if (pTargetPlot->isOwned())
			{
				if (isPotentialEnemy(pTargetPlot->getTeam(), pTargetPlot))
				{
					//Do not join groups which have debarked on an offensive mission
					return false;
				}
			}
		}
	}

	if (pUnit->getInvisibleType() != NO_INVISIBLE)
	{
		if (getInvisibleType() == NO_INVISIBLE)
		{
			return false;
		}
	}

	return true;
}

void CvUnitAI::resync(bool bWrite, ByteBuffer* pBuffer)
{
	CvUnit::resync(bWrite, pBuffer);

	RESYNC_INT(bWrite, pBuffer, m_iBirthmark);
	RESYNC_INT_WITH_CAST(bWrite, pBuffer, m_eUnitAIType, UnitAITypes);
	RESYNC_INT(bWrite, pBuffer, m_iAutomatedAbortTurn);
	RESYNC_INT(bWrite, pBuffer, m_iGarrisonCity);
	RESYNC_INT(bWrite, pBuffer, m_iGroupLeadOverride);
	RESYNC_BOOL(bWrite, pBuffer, m_bClaimedTerritory);
}


void CvUnitAI::read(FDataStreamBase* pStream)
{
	CvUnit::read(pStream);

	uint uiFlag=0;
	pStream->Read(&uiFlag);	// flags for expansion

	pStream->Read(&m_iBirthmark);

	pStream->Read((int*)&m_eUnitAIType);
	pStream->Read(&m_iAutomatedAbortTurn);

	//	Translate the unit AI id - done this way because unit AI types were
	//	not originally considered to be an enum type and so older saves have them
	//	as raw ints
	UnitAITypes eTranslatedUnitAI = (UnitAITypes)CvTaggedSaveFormatWrapper::getSaveFormatWrapper().getNewClassEnumValue(REMAPPED_CLASS_TYPE_UNITAIS, m_eUnitAIType, true);
	//	If the save has no translation table for unitAIs assume the ids are identical - this
	//	is normally the case, and we can't do any better with an older save
	if ( eTranslatedUnitAI != NO_UNITAI )
	{
		m_eUnitAIType = eTranslatedUnitAI;
	}
	//	Animals should never have a non-animal AI (old assets had a bug that allowed this
	//	so correct it here as a patch up)
	if ( isAnimal() && m_eUnitAIType != UNITAI_ANIMAL )
	{
		m_eUnitAIType = UNITAI_ANIMAL;

		GET_PLAYER(getOwner()).AI_noteUnitRecalcNeeded();
	}
	//	Invalid unitAIs cannot be coped with - just delete them - better than
	//	killing the entire game when this corruption is found
	if ( m_eUnitAIType >= NUM_UNITAI_TYPES )
	{
		kill(true);
	}

	CvTaggedSaveFormatWrapper&	wrapper = CvTaggedSaveFormatWrapper::getSaveFormatWrapper();

	wrapper.AttachToStream(pStream);
	WRAPPER_READ(wrapper, "CvUnitAI", &m_iGarrisonCity);	// which city does this unit belong to the garrison of (if any)
	WRAPPER_READ(wrapper, "CvUnitAI", &m_iGroupLeadOverride);
	WRAPPER_READ(wrapper, "CvUnitAI", &m_bClaimedTerritory);
}


void CvUnitAI::write(FDataStreamBase* pStream)
{
	CvUnit::write(pStream);

	uint uiFlag=0;
	pStream->Write(uiFlag);		// flag for expansion

	pStream->Write(m_iBirthmark);

	pStream->Write(m_eUnitAIType);
	pStream->Write(m_iAutomatedAbortTurn);

	CvTaggedSaveFormatWrapper&	wrapper = CvTaggedSaveFormatWrapper::getSaveFormatWrapper();

	wrapper.AttachToStream(pStream);
	WRAPPER_WRITE(wrapper, "CvUnitAI", m_iGarrisonCity);	// which city does this unit belong to the garrison of (if any)
	WRAPPER_WRITE(wrapper, "CvUnitAI", m_iGroupLeadOverride);
	WRAPPER_WRITE(wrapper, "CvUnitAI", m_bClaimedTerritory);
}

// Private Functions...

/************************************************************************************************/
/* BETTER_BTS_AI_MOD                      02/21/10                                jdog5000      */
/*                                                                                              */
/* Lead From Behind                                                                             */
/************************************************************************************************/
// Private Functions...
// Dale - RB: Field Bombard START
// RevolutionDCM - ranged bombardment
// returns true if a mission was pushed...
bool CvUnitAI::AI_RbombardPlot(int iRange, int iBonusValueThreshold)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns = 0;
	int iValue = 0;
	int iBestValue = 0;
	int iDX = 0, iDY = 0;
	pBestPlot = NULL;

	if(!GC.isDCM_RANGE_BOMBARD())
	{
		return false;
	}

	iSearchRange = AI_searchRange(iRange);

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot)	&& !pLoopPlot->isCity() && pLoopPlot->getImprovementType() != NO_IMPROVEMENT && pLoopPlot->getTeam() != getTeam())
				{	
					if (getGroup()->canBombardAtRanged(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						if (iBonusValueThreshold > 0)
						{
							ImprovementTypes eImprovement;
							if (pLoopPlot->getImprovementDuration() > ((pLoopPlot->isWater()) ? 20 : 5))
							{
								eImprovement = pLoopPlot->getImprovementType();
							}
							else
							{
								eImprovement = pLoopPlot->getRevealedImprovementType(getTeam(), false);
							}
							if (eImprovement != NO_IMPROVEMENT)
							{
								iValue = std::max(0, GC.getImprovementInfo(eImprovement).getPillageGold() - 10); // cottages = 0, hamlets = 5, villages = 10, towns = 15
								iValue *= 100;
								iValue /= 15; // cottages = 0, hamlets = 33, villages = 67, towns = 100
								if (pLoopPlot->getWorkingCity() == NULL)
								{
									iValue *= 50;
									iValue /= 100;
								}
								if (iValue < iBonusValueThreshold) iValue = 0;
							}
						} else
						{
							iValue = AI_pillageValue(pLoopPlot, 0); // returns any improvement with highest pillage value
						}
						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;
						}
					}
				}
			}
		}
	}
	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_RBOMBARD, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}
	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_RbombardUnit(int iRange, int iHighestOddsThreshold, int iMinStack, int iSeigeDiff, int iPowerThreshold)
{
	// iRange = bombard range to consider
	// iHighestOddsThreshold = the highest chance of successful attack
	// iMinStack = the minimum stack size to bombard
	// iSeigeDiff = the difference in range bombard capable seige, us to them
	// iPowerThreshold = comparison of stack strengths as a percent ration with 100 being equality

	PROFILE_FUNC();

	CvUnit* pDefender;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	if(!GC.isDCM_RANGE_BOMBARD())
	{
		return false;
	}

	iSearchRange = AI_searchRange(iRange);

	iBestValue = 999; // looking for the odds at or below iHighestOddsThreshold
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot) && !pLoopPlot->isCity())
				{
					if (getGroup()->canBombardAtRanged(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						if ((pLoopPlot->isVisible(getTeam(),false) && pLoopPlot->isVisibleEnemyUnit(this)) || AI_potentialEnemy(pLoopPlot->getTeam()))
						{
							if (pLoopPlot->getNumVisibleEnemyDefenders(this) >= iMinStack)
							{
								pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
								if (pDefender->isRbombardable(iMinStack))
								{
									iValue = AI_attackOdds(pLoopPlot, true);
									if (iValue <= iHighestOddsThreshold)
									{
										int ourSeige = getRbombardSeigeCount(plot());
										int theirSeige = pDefender->getRbombardSeigeCount(pLoopPlot);
										if ((ourSeige - theirSeige) >= iSeigeDiff)
										{
											int ourStrength = GET_PLAYER(getOwner()).AI_getOurPlotStrength(plot(), iRange, false, false) * 100;
											int theirStrength = GET_PLAYER(getOwner()).AI_getEnemyPlotStrength(plot(), iRange, false, false);
											if (theirStrength <= 0) theirStrength = 1;
											int strengthRatio = (ourStrength / theirStrength);
											if ((strengthRatio >= iPowerThreshold) && (theirStrength > 1))
											{
												if (iValue < iBestValue)
												{
													iBestValue = iValue;
													pBestPlot = pLoopPlot;
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	if (pBestPlot != NULL)
	{
		getGroup()->pushMission(MISSION_RBOMBARD, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
		return true;
	}
	return false;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_RbombardCity(CvCity* pCity)
{
	PROFILE_FUNC();

	CvUnit* pDefender;
	CvPlot* pPlot;

	if(!GC.isDCM_RANGE_BOMBARD())
	{
		return false;
	}

	if (pCity == NULL)
	{
		return false;
	}

	pPlot = pCity->plot();
	if (pPlot == NULL)
	{
		return false; // ok will never happen but anyway...
	}

	if(!getGroup()->canBombardAtRanged(plot(), pPlot->getX_INLINE(),pPlot->getY_INLINE()))
	{
		return false;
	}

	pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
	if (pDefender != NULL)
	{
		if (collateralDamageMaxUnits() > pPlot->getNumUnits())
		{
			if (pDefender->isRbombardable(3) && getGroup()->getBombardTurns(pCity) < 3)
			{
				getGroup()->pushMission(MISSION_RBOMBARD, pPlot->getX_INLINE(),pPlot->getY_INLINE());
				return true;
			}
		}
	}
	return false;
}
// From Lead From Behind by UncutDragon

void CvUnitAI::LFBgetBetterAttacker(CvUnit** ppAttacker, const CvPlot* pPlot, bool bPotentialEnemy, int& iAIAttackOdds, int& iAttackerValue) const
{
	CvUnit* pThis = (CvUnit*)this;
	CvUnit* pAttacker = (*ppAttacker);
	CvUnit* pDefender;
	int iOdds;
	int iValue;
	int iAIOdds;

	pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), pThis, !bPotentialEnemy, bPotentialEnemy);
	iValue = LFBgetAttackerRank(pDefender, iOdds);

	// Combat odds are out of 1000, but the AI routines need odds out of 100, and when called from AI_getBestGroupAttacker
	// we return this value. Note that I'm not entirely sure if/how that return value is actually used ... but just in case I
	// want to make sure I'm returning something consistent with what was there before
	iAIOdds = (iOdds + 5) / 10;
	iAIOdds += GET_PLAYER(getOwnerINLINE()).AI_getAttackOddsChange();
	iAIOdds = std::max(1, std::min(iAIOdds, 99));

	if (collateralDamage() > 0)
	{
		int iPossibleTargets = std::min((pPlot->getNumVisibleEnemyDefenders(pThis) - 1), collateralDamageMaxUnits());

		if (iPossibleTargets > 0)
		{
			iValue *= (100 + ((collateralDamage() * iPossibleTargets) / 5));
			iValue /= 100;
		}
	}

	// Nothing to compare against - we're obviously better
	if (!pAttacker)
	{
		(*ppAttacker) = pThis;
		iAIAttackOdds = iAIOdds;
		iAttackerValue = iValue;
		return;
	}

	// Compare our adjusted value with the current best
	if (iValue >= iAttackerValue)
	{
		(*ppAttacker) = pThis;
		iAIAttackOdds = iAIOdds;
		iAttackerValue = iValue;
	}
}
/************************************************************************************************/
/* BETTER_BTS_AI_MOD                       END                                                  */
/************************************************************************************************/

// RevolutionDCM - sea bombard AI identical to DCM 1.7 AI_RbombardCity() AI
// Returns true if a mission was pushed...
bool CvUnitAI::AI_RbombardNaval()
{
	PROFILE_FUNC();

	CvCity* pCity;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvUnit* pDefender;
	int iSearchRange;
	int iPotentialAttackers;
	int iValue;
	int iDamage;
	int iBestValue;
	int iDX, iDY;

	if(!canRBombard(plot()))
	{
		return false;
	}

	iSearchRange = getDCMBombRange();
	iBestValue = 0;
	pBestPlot = NULL;
	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
			if (pLoopPlot != NULL)
			{
				if (getGroup()->canBombardAtRanged(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
				{
					iValue = 0;
					pCity = pLoopPlot->getPlotCity();
					if (pCity != NULL)
					{
						iValue += std::max(0, (std::min((pCity->getDefenseDamage() + airBombCurrRate()), GC.getMAX_CITY_DEFENSE_DAMAGE()) - pCity->getDefenseDamage()));
						iValue *= 5;
						if (pCity->AI_isDanger())
						{
							iValue *= 2;
						}
						if (pCity == pCity->area()->getTargetCity(getOwnerINLINE()))
						{
							iValue *= 3;
						}
					}
					iPotentialAttackers = GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);//pLoopPlot->getNumVisibleEnemyDefenders(NO_PLAYER);
					if (iPotentialAttackers > 0 || pLoopPlot->isAdjacentTeam(getTeam()))
					{
						pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

						if( pDefender != NULL && pDefender->canDefend() )
						{
							iDamage = GC.getGameINLINE().getSorenRandNum(bombardRate(), "AI Bombard");
	//							iValue = max(0, (min((pDefender->getDamage() + iDamage), bombardRate()) - pDefender->getDamage()));
							iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);
							iValue *= (3 + iPotentialAttackers);
							iValue /= 4;
						}
					}
					iValue *= GC.getGameINLINE().getSorenRandNum(20, "AI Bombard");
					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						pBestPlot = pLoopPlot;
						FAssert(!atPlot(pBestPlot));
					}
				}
			}
		}
		if (pBestPlot != NULL)
		{
			getGroup()->pushMission(MISSION_RBOMBARD, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
			return true;
		}
	}
	return false;
}
// Dale - RB: Field Bombard END
// RevolutionDCM - end

// Dale - ARB: Archer Bombard START
// Returns true if a mission was pushed...
bool CvUnitAI::AI_Abombard()
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvUnit* pDefender;
	int iSearchRange;
	int iPotentialAttackers;
	int iValue;
	int iDamage;
	int iBestValue;
	int iDX, iDY;

	if(!canArcherBombard(plot()))
	{
		return false;
	}
	if (GC.getGameINLINE().getSorenRandNum(10, "Randomness") < 5)
	{
		return false;
	}
	if(GC.isDCM_ARCHER_BOMBARD())
	{
		iSearchRange = 1;
		iBestValue = 0;
		pBestPlot = NULL;
		for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
		{
			for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
			{
				pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
				if (pLoopPlot != NULL)
				{
					if (canArcherBombardAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						iValue = 0;
						iPotentialAttackers = pLoopPlot->getNumVisibleEnemyDefenders(this);//GET_PLAYER(getOwnerINLINE()).AI_adjacentPotentialAttackers(pLoopPlot);
						if (iPotentialAttackers > 0 || pLoopPlot->isAdjacentTeam(getTeam()))
						{
							pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

							if ( pDefender != NULL )
							{
								iDamage = std::max(1, ((GC.getDefineINT("COMBAT_DAMAGE") * (currFirepower(NULL, NULL) + ((currFirepower(NULL, NULL) + pDefender->currFirepower(NULL, NULL) + 1) / 2))) / (pDefender->currFirepower(pLoopPlot, this) + ((currFirepower(NULL, NULL) + pDefender->currFirepower(NULL, NULL) + 1) / 2))));
								iValue += (iDamage * iPotentialAttackers);

								iValue *= GC.getGameINLINE().getSorenRandNum(5, "AI Bombard");
								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = pLoopPlot;
									FAssert(!atPlot(pBestPlot));
								}
							}
						}
					}
				}
			}
		}
		if (pBestPlot != NULL)
		{
			getGroup()->pushMission(MISSION_ABOMBARD, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
			return true;
		}
	}
	return false;
}
// Dale - ARB: Archer Bombard END

// Dale - FE: Fighters START
bool CvUnitAI::AI_FEngage()
{
	PROFILE_FUNC();
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvUnit* pDefender;
	int iSearchRange;
	int iPotentialAttackers;
	int iValue;
	int iDamage;
	int iBestValue;
	int iDX, iDY;
	CLLNode<IDInfo>* pUnitNode;
	int iCount;

	if (!canFEngage(plot()))
	{
		return false;
	}
	if (currFirepower(NULL, NULL) <= 0)
	{
		return false;
	}
	if (GC.getGameINLINE().getSorenRandNum(10, "Randomness") < 5)
	{
		return false;
	}
	if(GC.isDCM_FIGHTER_ENGAGE())
	{
		iSearchRange = airRange();
		iBestValue = 0;
		pBestPlot = NULL;
		for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
		{
			for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
			{
				pLoopPlot	= plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
				if (pLoopPlot != NULL)
				{
					if (canFEngageAt(plot(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()))
					{
						iValue = 0;
						iCount = 0;
						pUnitNode = pLoopPlot->headUnitNode();
						while (pUnitNode != NULL)
						{
							pDefender = ::getUnit(pUnitNode->m_data);
							pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
							if (pDefender->getDomainType() == DOMAIN_AIR)
							{
								iCount++;
							}
						}
						iPotentialAttackers = iCount;
						iValue += iCount;
						if (iPotentialAttackers > 0 || pLoopPlot->isAdjacentTeam(getTeam()))
						{
							pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
							iDamage = std::max(1, ((GC.getDefineINT("COMBAT_DAMAGE") * (currFirepower(NULL, NULL) + ((currFirepower(NULL, NULL) + pDefender->currFirepower(NULL, NULL) + 1) / 2))) / (pDefender->currFirepower(pLoopPlot, this) + ((currFirepower(NULL, NULL) + pDefender->currFirepower(NULL, NULL) + 1) / 2))));
							iValue += (iDamage * pLoopPlot->getNumVisibleEnemyDefenders(this));
						}
						iValue *= GC.getGameINLINE().getSorenRandNum(5, "AI FEngage");
						if (iValue > iBestValue)
						{
//							for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; ++iPlayer)
//							{
//								AddDLLMessage((PlayerTypes)iPlayer, true, GC.getDefineINT("EVENT_MESSAGE_TIME"), "Got here!", "AS2D_BOMB_FAILS", MESSAGE_TYPE_INFO, GC.getUnitInfo(getUnitType()).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), plot()->getX_INLINE(), plot()->getY_INLINE());
//							}
							iBestValue = iValue;
							pBestPlot = pLoopPlot;
							FAssert(!atPlot(pBestPlot));
						}
					}
				}
			}
		}
		if (pBestPlot != NULL)
		{
			getGroup()->pushMission(MISSION_FENGAGE, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
			return true;
		}
	}
	return false;
}
// Dale - FE: Fighters END
/************************************************************************************************/
/* DCM                            END                                               Glider1     */
/************************************************************************************************/

/**** Dexy - Fixed Borders START ****/
// Returns true if a mission was pushed...
#ifdef USE_REACHABLE_ENUMERATION
bool CvUnitAI::AI_claimForts(CvReachablePlotSet* pReachablePlots, int iMinValue, int iMaxPath)
#else
bool CvUnitAI::AI_claimForts(int iMinValue, int iMaxPath)
#endif
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pFortPlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iJ;

	iBestValue = iMinValue;
	pBestPlot = NULL;
	pFortPlot = NULL;


#ifdef USE_REACHABLE_ENUMERATION
	for(CvReachablePlotSet::const_iterator itr = pReachablePlots->begin(); itr != pReachablePlots->end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif
		if (pLoopPlot->getImprovementType() != NO_IMPROVEMENT && GC.getImprovementInfo(pLoopPlot->getImprovementType()).isActsAsCity())
		{
			if (/*AI_plotValid(pLoopPlot) &&*/ pLoopPlot->area() == area())
			{
				if (potentialWarAction(pLoopPlot) || pLoopPlot->getOwnerINLINE() == NO_PLAYER)
				{			    
					if (canClaimTerritory(pLoopPlot))
					{
						if (!AI_isPlotWellDefended(pLoopPlot, true, 35))
						{
							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_CLAIM_TERRITORY, getGroup()) == 0)
							{
								if (generatePath(pLoopPlot, 0, true, &iPathTurns, iMaxPath))
								{
									iValue = 1000;
									
									for (iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
									{
										CvPlot* pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iJ));

										if (pAdjacentPlot != NULL)
										{
											if (pAdjacentPlot->getBonusType(getTeam()) != NO_BONUS)
											{
												iValue *= 2;
											}
										}
									}

									iValue /= (iPathTurns + 1);

									if (iValue > iBestValue)
									{
										CvPlot* endTurnPlot = getPathEndTurnPlot();

										if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 60) )
										{
											iBestValue = iValue;
											pBestPlot = endTurnPlot;
											pFortPlot = pLoopPlot;
										}
									}
								}
							}
						}
					}			    
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pFortPlot != NULL))
	{
		if (atPlot(pFortPlot))
		{
			if (isEnemy(pFortPlot->getTeam()))
			{
				getGroup()->pushMission(MISSION_CLAIM_TERRITORY, -1, -1, 0, false, false, MISSIONAI_CLAIM_TERRITORY, pFortPlot);
				return true;
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_CLAIM_TERRITORY, pFortPlot);
		}
	}

	return false;
}

bool CvUnitAI::AI_guardClaimedResource()
{
	CvPlot* pPlot = plot();
	if (pPlot->getOwnerINLINE() == getOwnerINLINE())
	{
		//If we aren't the "true" cultural owners of the tile, we must be claiming the territory
		if (pPlot->calculateCulturalOwner(true) != getOwnerINLINE() && pPlot->calculateCulturalOwner(false) == getOwnerINLINE())
		{
			if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(plot(), MISSIONAI_CLAIM_TERRITORY, getGroup()) == 0)
			{
				if (!exposedToDanger(plot(), 50))
				{
					getGroup()->pushMission(MISSION_SKIP, -1, -1, 0, false, false, MISSIONAI_CLAIM_TERRITORY, plot());
					finishMoves();
					m_bClaimedTerritory = true;
					return true;
				}
			}
		}
	}
	return false;
}

#ifdef USE_REACHABLE_ENUMERATION
bool CvUnitAI::AI_claimResources(CvReachablePlotSet* pReachablePlots, int iMinValue, int iMaxPath)
#else
bool CvUnitAI::AI_claimResources(int iMinValue, int iMaxPath)
#endif
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pResourcePlot;
	int iPathTurns;
	int iValue;
	int iBestValue;

	iBestValue = iMinValue;
	pBestPlot = NULL;
	pResourcePlot = NULL;

	if (GET_PLAYER(getOwnerINLINE()).AI_getNumAIUnits(UNITAI_WORKER) <= 0)
	{
		return false;
	}

#ifdef USE_REACHABLE_ENUMERATION
	for (CvReachablePlotSet::const_iterator itr = pReachablePlots->begin(); itr != pReachablePlots->end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif
		BonusTypes eBonus = pLoopPlot->getBonusType(getTeam());
		if (eBonus != NO_BONUS)
		{
			if (pLoopPlot->area() == area())
			{
				if (potentialWarAction(pLoopPlot) || pLoopPlot->getOwnerINLINE() == NO_PLAYER)
				{
					if (canClaimTerritory(pLoopPlot) && pLoopPlot->getClaimingOwner() != getOwnerINLINE())
					{
						//Already improved
						bool bCanWork = pLoopPlot->getImprovementType() != NO_IMPROVEMENT && GC.getImprovementInfo(pLoopPlot->getImprovementType()).isImprovementBonusMakesValid(eBonus);

						for (int iJ = 0; iJ < GC.getNumImprovementInfos(); iJ++)
						{
							if (bCanWork)
							{
								break;
							}
							if (GC.getImprovementInfo((ImprovementTypes)iJ).isImprovementBonusMakesValid(eBonus) && pLoopPlot->canHaveImprovement((ImprovementTypes)iJ))
							{
								for (int iK = 0; iK < GC.getNumBuildInfos(); iK++)
								{
									CvBuildInfo& kBuild = GC.getBuildInfo((BuildTypes)iK);
									if (kBuild.getImprovement() == iJ)
									{
										if (GET_PLAYER(getOwnerINLINE()).canBuild(NULL, (BuildTypes)iK, true, true, false))
										{
											//Do we have prereq techs?
											if (kBuild.getTechPrereq() != NO_TECH)
											{
												if (!(GET_TEAM(getTeam()).isHasTech((TechTypes)kBuild.getTechPrereq())))
												{
													break;
												}
											}

											//Is the build obsolete?
											if (kBuild.getObsoleteTech() != NO_TECH)
											{
												if (GET_TEAM(getTeam()).isHasTech((TechTypes)kBuild.getObsoleteTech()))
												{
													break;
												}
											}

											//Do we have the improvement prereq techs?
											if (kBuild.getImprovement() != NO_IMPROVEMENT)
											{
												if (GC.getImprovementInfo((ImprovementTypes)kBuild.getImprovement()).getPrereqTech() != NO_TECH)
												{
													if (!GET_TEAM(getTeam()).isHasTech((TechTypes)GC.getImprovementInfo((ImprovementTypes)kBuild.getImprovement()).getPrereqTech()))
													{
														break;
													}
												}
											}

											bCanWork = true;
											break;
										}
									}
								}
							}
						}

						if (bCanWork && GET_PLAYER(getOwnerINLINE()).AI_bonusVal(eBonus) > 0 && GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_CLAIM_TERRITORY, getGroup()) == 0)
						{
							if (generatePath(pLoopPlot, 0, true, &iPathTurns, iMaxPath))
							{
								iValue = 100000;

								iValue /= (iPathTurns + 1);

								if (iValue > iBestValue)
								{
									CvPlot* endTurnPlot = getPathEndTurnPlot();

									if (endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 60))
									{
										iBestValue = iValue;
										pBestPlot = endTurnPlot;
										pResourcePlot = pLoopPlot;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pResourcePlot != NULL))
	{
		if (atPlot(pResourcePlot))
		{
			getGroup()->pushMission(MISSION_CLAIM_TERRITORY, -1, -1, 0, false, false, MISSIONAI_CLAIM_TERRITORY, pResourcePlot);
			m_bClaimedTerritory = true;
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_CLAIM_TERRITORY, pResourcePlot);
		}
	}

	return false;
}


BuildTypes CvUnitAI::AI_findBestFort(CvPlot* pPlot) const
{
	PROFILE_FUNC();
	int iBestTempBuildValue = 0;
	BuildTypes eBestTempBuild = NO_BUILD;
	
	for (int iI = 0; iI < GC.getNumBuildInfos(); iI++)
	{
		BuildTypes eBuild = ((BuildTypes)iI);

		if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
		{
			if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).isActsAsCity())
			{
				if (GC.getImprovementInfo((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement())).getDefenseModifier() > 0)
				{
					if (canBuild(pPlot, eBuild))
					{
						int iValue = 10000;

						iValue /= (GC.getBuildInfo(eBuild).getTime() + 1);

						if (iValue < iBestTempBuildValue)
						{
							iBestTempBuildValue = iValue;
							eBestTempBuild = eBuild;
						}
					}
				}
			}
		}
	}
	
	return eBestTempBuild;
}

bool CvUnitAI::AI_StrategicForts()
{
	PROFILE_FUNC();

	int iBestValue = 0;
	BuildTypes eBestBuild = NO_BUILD;
	CvPlot* pLoopPlot = NULL;
	CvPlot* pBestPlot = NULL;
	bool bWarPlan = GET_TEAM(getTeam()).getAnyWarPlanCount(true) > 0;
	if (isBarbarian())
	{
		return false;
	}
	
	CvPlayerAI& kOwner = GET_PLAYER(getOwnerINLINE());
#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif

		if (/*AI_plotValid(pLoopPlot) &&*/ pLoopPlot->area() == area())
		{
			if (pLoopPlot->getOwnerINLINE() == NO_PLAYER || pLoopPlot->getTeam() == getTeam())
			{
				if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
				{
					BuildTypes eBestTempBuild = AI_findBestFort(pLoopPlot);
					
					if (eBestTempBuild != NO_BUILD)
					{
						int iValue = std::max(100, pLoopPlot->getFoundValue(getOwnerINLINE()));
						iValue *= (pLoopPlot->getBorderPlotCount() + 1);
						iValue *= ((pLoopPlot->getEnemyBorderPlotCount(getOwnerINLINE()) + 1) * (bWarPlan ? 3 : 1));
						iValue /= (GC.getBuildInfo(eBestTempBuild).getTime() + 1);

						if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
						{
							if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_BUILD, getGroup(), 3) == 0)
							{
								int iPathTurns;
								if (generatePath(pLoopPlot, 0, true, &iPathTurns))
								{
									iValue *= 1000;
									iValue /= (iPathTurns + 1);

									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										eBestBuild = eBestTempBuild;
										pBestPlot = pLoopPlot;
									}
								}
							}
						}
					}
				}
			}
		}
	}
	
	//No real value
	if (iBestValue < 250)
	{
		return false;
	}

	if (pBestPlot != NULL)
	{
		FAssertMsg(eBestBuild != NO_BUILD, "BestBuild is not assigned a valid value");
		FAssertMsg(eBestBuild < GC.getNumBuildInfos(), "BestBuild is assigned a corrupt value");

		getGroup()->pushMission(MISSION_ROUTE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_BUILD, pBestPlot);
		getGroup()->pushMission(MISSION_BUILD, eBestBuild, -1, 0, (getGroup()->getLengthMissionQueue() > 0), false, MISSIONAI_BUILD, pBestPlot);

		return true;
	}
	return false;
}

bool CvUnitAI::AI_caravan(bool bAnyCity)
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestHurryPlot;
	bool bHurry;
	int iTurnsLeft;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;
	int iNumCities = GET_PLAYER(getOwnerINLINE()).getNumCities();

	iBestValue = 0;
	pBestPlot = NULL;
	pBestHurryPlot = NULL;

	//Avoid using Great People
	if (getUnitInfo().getProductionCost() <= 0)
	{
		return false;
	}

	if (iNumCities < 0)
	{
		return false;
	}
	
	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
		{
			if ( canHurry(pLoopCity->plot()))
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
					if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true, &iPathTurns))
					{
						bHurry = false;
						if (!bAnyCity)
						{
							if (pLoopCity->findPopulationRank() >= ((iNumCities * 2) / 3))
							{
								int iPopulation = pLoopCity->getPopulation();
								int iEmpirePop = GET_PLAYER(getOwnerINLINE()).getTotalPopulation();
								int iAvgPop = iEmpirePop / iNumCities;
								if (iPopulation < ((iAvgPop * 2) / 3))
								{
									bHurry = true;
								}
							}
						}


						if (bHurry || bAnyCity)
						{
							iTurnsLeft = pLoopCity->getProductionTurnsLeft();

							iTurnsLeft -= iPathTurns;
							int iMinTurns = 2;
							iMinTurns *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getAnarchyPercent();
							iMinTurns /= 100;


							if (iTurnsLeft > iMinTurns)
							{
								iValue = iTurnsLeft;


								if (iValue > iBestValue)
								{
									iBestValue = iValue;
									pBestPlot = getPathEndTurnPlot();
									pBestHurryPlot = pLoopCity->plot();

								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestHurryPlot != NULL))
	{
		if (atPlot(pBestHurryPlot))
		{
			getGroup()->pushMission(MISSION_HURRY);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY, false, false, MISSIONAI_HURRY, pBestHurryPlot);
		}
	}

	return false;
}

bool CvUnitAI::AI_hurryFood()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	CvPlot* pBestHurryPlot;
	bool bHurry;
	int iTurnsLeft;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iLoop;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestHurryPlot = NULL;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
		{
			if (canHurry(pLoopCity->plot()))
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
					if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopCity->plot(), MISSIONAI_HURRY_FOOD, getGroup()) == 0)
					{
						if (generatePath(pLoopCity->plot(), MOVE_NO_ENEMY_TERRITORY, true, &iPathTurns))
						{
							bHurry = false;
							
							if (pLoopCity->foodDifference() < 0)
							{
								if ((pLoopCity->foodDifference() == -1) && (pLoopCity->getFood() >= ((75 * pLoopCity->growthThreshold()) / 100)))
								{//if the city is stagnate
									bHurry = true;
								}
								else
								{//if the city is shrinking
									bHurry = true;
								}
							}
							if (!bHurry)
							{
								//if we are a smaller city
								int iRand = GC.getGameINLINE().getSorenRandNum(100, "AI hurry with food");
								if (iRand > 75)
								{
									if (pLoopCity->findPopulationRank() > GC.getWorldInfo(GC.getMapINLINE().getWorldSize()).getTargetNumCities())
									{
										bHurry = true;
									}
								}
							}

							if (bHurry)
							{
								iTurnsLeft = pLoopCity->getFoodTurnsLeft();

								iTurnsLeft -= iPathTurns;

								if (iTurnsLeft > 10)
								{
									iValue = iTurnsLeft;

									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
										pBestHurryPlot = pLoopCity->plot();
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestHurryPlot != NULL))
	{
		if (atPlot(pBestHurryPlot))
		{
			getGroup()->pushMission(MISSION_HURRY_FOOD);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_NO_ENEMY_TERRITORY, false, false, MISSIONAI_HURRY_FOOD, pBestHurryPlot);
		}
	}

	return false;
}

bool CvUnitAI::AI_command()
{
	if (!GC.getGameINLINE().isOption(GAMEOPTION_GREAT_COMMANDERS))
	{
		return false;
	}
	
	int iNeededCommanders = 1 + (GET_PLAYER(getOwnerINLINE()).getNumCities() / 5);
	int iHaveCommanders = (int)GET_PLAYER(getOwner()).Commanders.size();

	for (int iPlayer = 0; iPlayer < MAX_PLAYERS; iPlayer++)
	{
		if (!GET_PLAYER((PlayerTypes)iPlayer).isMinorCiv() && GET_TEAM(GET_PLAYER((PlayerTypes)iPlayer).getTeam()).isAtWar(getTeam()))
		{
			if (GET_PLAYER(getOwnerINLINE()).Commanders.size() < GET_PLAYER((PlayerTypes)iPlayer).Commanders.size())
			{
				iNeededCommanders++;
				break;
			}
		}
	}

	if (iNeededCommanders > iHaveCommanders)
	{
		setCommander(true);
		return true;
	}
	return false;
}

bool CvUnitAI::AI_AutomatedPillage(int iBonusValueThreshold)
{
	PROFILE_FUNC();
	
	FAssertMsg(isHuman(), "should not be called for AI's");

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	CvPlot* pBestPillagePlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	pBestPlot = NULL;
	pBestPillagePlot = NULL;

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (AI_plotValid(pLoopPlot) && getGroup()->canPillage(pLoopPlot) && pLoopPlot->area() == area())
		{
			if (pLoopPlot->getOwnerINLINE() != BARBARIAN_PLAYER || !GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PILLAGE_AVOID_BARBARIAN_CITIES))
			{
				if (potentialWarAction(pLoopPlot))
				{
					if (GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PILLAGE_AVOID_ENEMY_UNITS) || !pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
					{
						if (GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pLoopPlot, MISSIONAI_PILLAGE, getGroup(), 1) == 0)
						{
							if (generatePath(pLoopPlot, 0, true, &iPathTurns))
							{
								iValue = AI_pillageValue(pLoopPlot, iBonusValueThreshold);

								iValue *= 1000;

								iValue /= (iPathTurns + 1);

								// if not at war with this plot owner, then devalue plot if we already inside this owner's borders
								// (because declaring war will pop us some unknown distance away)
								if (!isEnemy(pLoopPlot->getTeam()) && plot()->getTeam() == pLoopPlot->getTeam())
								{
									iValue /= 10;
								}

								if (iValue > iBestValue)
								{
									CvPlot* endTurnPlot = getPathEndTurnPlot();

									if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 60) )
									{
										iBestValue = iValue;
										pBestPlot = endTurnPlot;
										pBestPillagePlot = pLoopPlot;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (pBestPillagePlot != NULL))
	{
		if (atPlot(pBestPillagePlot) && !isEnemy(pBestPillagePlot->getTeam()))
		{
			return false;
		}
		
		if (atPlot(pBestPillagePlot))
		{
			if (isEnemy(pBestPillagePlot->getTeam()))
			{
				getGroup()->pushMission(MISSION_PILLAGE, -1, -1, 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
				return true;
			}
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), 0, false, false, MISSIONAI_PILLAGE, pBestPillagePlot);
		}
	}

	return false;
}


void CvUnitAI::AI_SearchAndDestroyMove(bool bWithCommander)
{
	PROFILE_FUNC();
	int iMinimumOdds = isHuman() ? GET_PLAYER(getOwnerINLINE()).getModderOption(MODDEROPTION_AUTO_HUNT_MIN_COMBAT_ODDS) : (bWithCommander ? 80 : 60);

	MissionAITypes eMissionAIType = MISSIONAI_GROUP;
	if( !isHuman() && GET_PLAYER(getOwnerINLINE()).AI_unitTargetMissionAIs(this, &eMissionAIType, 1, getGroup(), 1) > 0 )
	{
		// Wait for units which are joining our group this turn
		getGroup()->pushMission(MISSION_SKIP);
		return;
	}

	if ( !isHuman() && plot()->getOwnerINLINE() != getOwnerINLINE() )
	{
		if ( AI_groupMergeRange(UNITAI_SUBDUED_ANIMAL, 0, false, true, true) )
		{
			return;
		}
		//	In the worker case we don't want to get sucked into a stack with an already protected
		//	worker, or one not also in non-owned teritory so just search this plot
		if ( AI_group(UNITAI_WORKER, 1, -1, -1, false, false, false, 0) )
		{
			return;
		}
	}

	//	If we have any animal hangers-on and are in our territory drop them off
	if ( !isHuman() && (getGroup()->countNumUnitAIType(UNITAI_SUBDUED_ANIMAL) > 0 || getGroup()->countNumUnitAIType(UNITAI_WORKER) > 0) && plot()->getOwnerINLINE() == getOwnerINLINE() )
	{
		getGroup()->AI_separateAI(UNITAI_SUBDUED_ANIMAL);
	}

	if (getGroup()->getWorstDamage() > 0)
	{
		bool	bHasTerrainDamage = (plot()->getTerrainTurnDamage(this) > 0 ||
									(plot()->getFeatureTurnDamage() > 0));

		OutputDebugString(CvString::format("%S (%d) damaged at (%d,%d)...\n",getDescription().c_str(),m_iID,m_iX,m_iY).c_str());
		//	If there is an adjacent enemy seek safety before we heal
		if ( exposedToDanger(plot(), 80) )
		{
			OutputDebugString("    ...plot is dangerous - seeking safety\n");
			if ( AI_safety() )
			{
				return;
			}
		}

		if (!bHasTerrainDamage)
		{
			OutputDebugString(CvString::format("    ...healing at (%d,%d)\n",m_iX,m_iY).c_str());
			getGroup()->pushMission(MISSION_HEAL);
			return;
		}
		else if ( getGroup()->getWorstDamage() > 25 )
		{
			//	Look for somewhere safer
			if ( AI_safety(3) )
			{
				return;
			}
		}
	}

	if (AI_goody(4))
	{
		return;
	}

	//	If anyone is actively asking for a hunter that takes priority
	if ( !bWithCommander && !isHuman() && processContracts(HIGHEST_PRIORITY_ESCORT_PRIORITY) )
	{
		return;
	}
	
	if (AI_huntRange(1, iMinimumOdds, false))
	{
		return;
	}

	//	If we have more than 2 animal hangers-on escort them back to our territory
	if ( !isHuman() && (getGroup()->countNumUnitAIType(UNITAI_WORKER) + getGroup()->countNumUnitAIType(UNITAI_SUBDUED_ANIMAL) > 2) && plot()->getOwnerINLINE() != getOwnerINLINE() )
	{
		if (AI_retreatToCity())
		{
			return;
		}
	}
	
	if (AI_huntRange(2, iMinimumOdds, false))
	{
		return;
	}
	
	if (AI_refreshExploreRange(2, false))
	{
		return;
	}
	
	if (AI_huntRange(3, iMinimumOdds, false))
	{
		return;
	}

	if (AI_refreshExploreRange(3, false))
	{
		return;
	}
	
	if (AI_huntRange(5, iMinimumOdds, false))
	{
		return;
	}

	if (AI_refreshExploreRange(3, true))
	{
		return;
	}

	if (AI_travelToUpgradeCity())
	{
		return;
	}

	//	If we have animal hangers-on escort them back to our territory
	if ( !isHuman() && (getGroup()->countNumUnitAIType(UNITAI_SUBDUED_ANIMAL) > 0 || getGroup()->countNumUnitAIType(UNITAI_WORKER) > 0) && plot()->getOwnerINLINE() != getOwnerINLINE() )
	{
		if (AI_retreatToCity())
		{
			return;
		}
	}

	if (!isHuman() && GET_PLAYER(getOwnerINLINE()).calculateUnitCost() > 0)
	{
		int iNeededHunters = GET_PLAYER(getOwnerINLINE()).AI_neededHunters(area());
		int iHasHunters = GET_PLAYER(getOwnerINLINE()).AI_totalAreaUnitAIs(area(), UNITAI_HUNTER);
		
		if ( iHasHunters > iNeededHunters + 1 )
		{
			if( gUnitLogLevel >= 2 )
			{
				logBBAI("%S has %d hunters (%d needed) - scrapping",GET_PLAYER(getOwnerINLINE()).getCivilizationDescription(0), iHasHunters, iNeededHunters);
			}
			scrap();
			return;
		}
	}

	if (AI_moveToBorders())
	{
		return;
	}

	if (AI_patrol())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

bool CvUnitAI::AI_huntRange(int iRange, int iOddsThreshold, bool bStayInBorders, int iMinValue)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;
	
	bool bCanCaptureCities = !GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_HUNT_NO_CITY_CAPTURING) && getGroup()->getAutomateType() == AUTOMATE_HUNT;
	if (bCanCaptureCities)
	{
		bCanCaptureCities = !GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PATROL_NO_CITY_CAPTURING) && getGroup()->getAutomateType() == AUTOMATE_BORDER_PATROL;
	}

	iSearchRange = iRange;

	iBestValue = iMinValue;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (AI_plotValid(pLoopPlot))
				{
					if (!bStayInBorders || (pLoopPlot->getOwnerINLINE() == getOwnerINLINE()))
					{
						if (!pLoopPlot->isCity() || bCanCaptureCities)
						{
							if (pLoopPlot->isVisible(getTeam(),false) && pLoopPlot->isVisibleEnemyUnit(this))
							{
								if (!atPlot(pLoopPlot) && getGroup()->canMoveInto(pLoopPlot, true) && generatePath(pLoopPlot, 0, true, &iPathTurns, iRange))
								{
									if (pLoopPlot->getNumVisibleEnemyDefenders(this) <= getGroup()->getNumUnits())
									{
										iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

										if (iValue >= AI_finalOddsThreshold(pLoopPlot, iOddsThreshold))
										{
											if (!exposedToDanger(pLoopPlot, iOddsThreshold))
											{
												if (iValue > iBestValue)
												{
													CvPlot* endTurnPlot = getPathEndTurnPlot();

													if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, iOddsThreshold) )
													{
														iBestValue = iValue;
														pBestPlot = endTurnPlot;
														FAssert(!atPlot(pBestPlot));
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_DIRECT_ATTACK, false, false);
	}

	return false;
}

void CvUnitAI::AI_nationalDefense()
{

	int iMinimumOdds = GET_PLAYER(getOwnerINLINE()).getModderOption(MODDEROPTION_AUTO_NATIONAL_DEFENSE_MIN_COMBAT_ODDS);

	if (AI_returnToBorders())
	{
		return;
	}

	if (AI_isEssentialDefender()) 
	{
		return;
	}

	if (getDamage() > 25)
	{
		if (AI_heal())
		{
			return;
		}
	}

	if (AI_enemyInsideNationalBorders())
	{
		AI_setUnitAIType(UNITAI_ATTACK);
		if (AI_leaveAttack(2, iMinimumOdds, 100, true, true))
		{
			return;
		}

		if (AI_leaveAttack(5, iMinimumOdds, 100, true, true))
		{
			return;
		}

		if (AI_group(AI_getUnitAIType(), 3, -1, -1, false, false, false, 3, false, false, false, NO_MISSIONAI, AUTOMATE_NATIONAL_DEFENSE)) {
			getGroup()->setAutomateType(AUTOMATE_NATIONAL_DEFENSE);
			return;
		}

		if (AI_guardCityMinDefender(false))
		{
			return;
		}

		if (AI_leaveAttack(6, iMinimumOdds, 100, true, true))
		{
			return;
		}

		if (AI_leaveAttack(9, iMinimumOdds, 100, true, true))
		{
			return;
		}

		if (AI_guardCityMinDefender(true))
		{
			return;
		}

		if (AI_group(AI_getUnitAIType(), 5, -1, -1, false, false, false, 6, false, false, false, NO_MISSIONAI, AUTOMATE_NATIONAL_DEFENSE)) {
			getGroup()->setAutomateType(AUTOMATE_NATIONAL_DEFENSE);
			return;
		}

		if (AI_leaveAttack(10, iMinimumOdds, 100, true, true))
		{
			return;
		}

		if (AI_guardCity(true, true))
		{
			return;
		}

		if (AI_group(AI_getUnitAIType(), -1, -1, -1, false, false, false, 10, true, false, false, NO_MISSIONAI, AUTOMATE_NATIONAL_DEFENSE)) {
			getGroup()->setAutomateType(AUTOMATE_NATIONAL_DEFENSE);
			return;
		}

		if (AI_leaveAttack(16, iMinimumOdds, 100, true, true))
		{
			return;
		}

		AI_setUnitAIType(UNITAI_CITY_DEFENSE);
	}
	else if(getGroup()->getNumUnits() > 1) {
		//Split up any grouped units
		CvSelectionGroup* pOtherGroup = NULL;
		CvSelectionGroup* pSplitGroup = getGroup()->splitGroup(1, this, &pOtherGroup);
		if (pOtherGroup != NULL)
		{
			pOtherGroup->setAutomateType(AUTOMATE_NATIONAL_DEFENSE);
		}
		getGroup()->setAutomateType(AUTOMATE_NATIONAL_DEFENSE);
	}

	if (AI_shuffleNationalDefenders(iMinimumOdds))
	{
		return;
	}

	if (AI_heal())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	if (plot()->isCity() && plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		getGroup()->pushMission(MISSION_FORTIFY);
	}
	else
	{
		getGroup()->pushMission(MISSION_SKIP);
	}	return;
}

bool CvUnitAI::AI_shuffleNationalDefenders(int iOddsThreshold)
{
	CvCity* pLoopCity;
	CvCity* pBestCity = NULL;
	int iBestValue = 0;
	int iLoop;
	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		int iCityDefenderCount = pLoopCity->plot()->getNumActiveDefenders(getOwnerINLINE());
		int iNeededDefenders = pLoopCity->AI_neededDefenders();
		int iIncomingDefenders = GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIsInternal(pLoopCity->plot(), MISSIONAI_GUARD_CITY, 0, NULL, getGroup());
		int iMissingDefenders = std::max(0, iNeededDefenders - (iCityDefenderCount + iIncomingDefenders));
		int iPathTurns;

		if (AI_getUnitAIType() != UNITAI_CITY_DEFENSE && atPlot(pLoopCity->plot()))
		{
			iCityDefenderCount++;
		}
		if (generatePath(pLoopCity->plot(), 0, true, &iPathTurns))
		{
			int iValue = 100000 * std::max(1, pLoopCity->getPopulation() / 3);
			iValue /= std::max(1, iCityDefenderCount + iIncomingDefenders);
			iValue /= (1 + iPathTurns);
			iValue *= std::max(1, (iMissingDefenders + 1) * (iMissingDefenders + 1) * (iMissingDefenders + 1));

			if (iValue > iBestValue)
			{
				CvPlot* endTurnPlot = getPathEndTurnPlot();

				if (endTurnPlot == pLoopCity->plot() || !exposedToDanger(endTurnPlot, iOddsThreshold))
				{
					iBestValue = iValue;
					pBestCity = pLoopCity;
				}
			}
		}
	}
	if (pBestCity != NULL)
	{
		if (!atPlot(pBestCity->plot()))
		{
			getGroup()->AI_setAsGarrison(pBestCity);
			AI_setUnitAIType(UNITAI_CITY_DEFENSE);
			getGroup()->pushMission(MISSION_MOVE_TO, pBestCity->getX_INLINE(), pBestCity->getY_INLINE(), 0, false, false, MISSIONAI_GUARD_CITY, pBestCity->plot());
			return true;
		}
	}
	return false;
}

bool CvUnitAI::AI_enemyInsideNationalBorders()
{
	PlayerTypes eOwner = getOwnerINLINE();
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
		if (pLoopPlot->getOwnerINLINE() == eOwner) {
			if (pLoopPlot->isVisibleEnemyUnit(this))
			{
				return true;
			}
		}
	}
	return false;
}

bool CvUnitAI::AI_isEssentialDefender()
{
	CvCity* pPlotCity = plot()->getPlotCity();
	if ((pPlotCity != NULL) && (pPlotCity->getOwnerINLINE() == getOwnerINLINE()))
	{
		int iCityDefenderCount = pPlotCity->plot()->plotCount(PUF_isUnitAIType, UNITAI_CITY_DEFENSE, -1, getOwnerINLINE());
		//Require between 1-3 defenders, based on era
		int iEssentialDefenderCount = std::min(3, std::max(1, GET_PLAYER(getOwnerINLINE()).getCurrentEra() / 2));
		if (iCityDefenderCount <= iEssentialDefenderCount)
		{
			AI_setUnitAIType(UNITAI_CITY_DEFENSE);
			getGroup()->pushMission(MISSION_FORTIFY, -1, -1, 0, false, false, MISSIONAI_GUARD_CITY, NULL);
			getGroup()->AI_setAsGarrison(pPlotCity);
			return true;
		}
	}
	return false;
}

void CvUnitAI::AI_cityDefense()
{

	int iMinimumOdds = GET_PLAYER(getOwnerINLINE()).getModderOption(MODDEROPTION_AUTO_DEFENSE_MIN_COMBAT_ODDS);
	bool bCanLeaveCity = GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_DEFENSE_CAN_LEAVE_CITY);

	if (AI_returnToBorders())
	{
		return;
	}

	if (AI_guardCityBestDefender())
	{
		return;
	}
	
	if (AI_guardCityMinDefender(false))
	{
		return;
	}
	
	if (AI_leaveAttack(2, iMinimumOdds, 100))
	{
		return;
	}
	
	if (AI_leaveAttack(3, iMinimumOdds + 10, 130))
	{
		return;
	}
	
	if (AI_guardCity(bCanLeaveCity, bCanLeaveCity))
	{
		return;
	}
	
	if (AI_heal())
	{
		return;
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

void CvUnitAI::AI_borderPatrol()
{
	PROFILE_FUNC();
	
	bool bStayInBorders = !GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PATROL_CAN_LEAVE_BORDERS);
	int iMinimumOdds = GET_PLAYER(getOwnerINLINE()).getModderOption(MODDEROPTION_AUTO_PATROL_MIN_COMBAT_ODDS);

	if (AI_returnToBorders())
	{
		return;
	}
	
	if (AI_heal())
	{
		return;
	}
	
	if (AI_huntRange(1, iMinimumOdds, bStayInBorders))
	{
		return;
	}
	
	if (AI_huntRange(2, iMinimumOdds, bStayInBorders))
	{
		return;
	}
	
	if (AI_huntRange(3, iMinimumOdds, true))
	{
		return;
	}
	
	if (AI_huntRange(5, iMinimumOdds + 5, true))
	{
		return;
	}
	
	if (AI_patrolBorders())
	{
		return;
	}

	if (AI_huntRange(7, iMinimumOdds + 10, true))
	{
		return;
	}
	
	if (AI_huntRange(12, iMinimumOdds + 15, true))
	{
		return;
	}
	
	if (!bStayInBorders)
	{
		if (AI_patrol())
		{
			return;
		}
	}

	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

bool CvUnitAI::AI_returnToBorders()
{
	PROFILE_FUNC();
	
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iI;

	iBestValue = 0;
	pBestPlot = NULL;
	
	//Allows the unit to be a maximum of 2 tiles from our borders before ordering him back
	if (plot()->getOwnerINLINE() == getOwnerINLINE())
	{
		return false;
	}
	CvPlot* pAdjacentPlot;
	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
		if (pAdjacentPlot != NULL)
		{
			if (pAdjacentPlot->getOwnerINLINE() == getOwnerINLINE())
			{
				return false;
			}
			CvPlot* pAdjacentPlot2;
			for (int iJ = 0; iJ < NUM_DIRECTION_TYPES; iJ++)
			{
				pAdjacentPlot2 = plotDirection(pAdjacentPlot->getX_INLINE(), pAdjacentPlot->getY_INLINE(), ((DirectionTypes)iJ));
				if (pAdjacentPlot2 != NULL)
				{
					if (pAdjacentPlot2->getOwnerINLINE() == getOwnerINLINE())
					{
						return false;
					}
				}
			}
		}
	}

#ifdef USE_REACHABLE_ENUMERATION
	CvReachablePlotSet plotSet(getGroup(), 0, MAX_INT);

	for(CvReachablePlotSet::const_iterator itr = plotSet.begin(); itr != plotSet.end(); ++itr)
	{
		pLoopPlot = itr.plot();
#else
	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
#endif
		if (/*AI_plotValid(pLoopPlot) &&*/ pLoopPlot->area() == area())
		{
			if (pLoopPlot->getOwnerINLINE() == getOwnerINLINE())
			{
				if (!pLoopPlot->isVisible(getTeam(),false) || !pLoopPlot->isVisibleEnemyUnit(this))
				{
					if (generatePath(pLoopPlot, 0, true, &iPathTurns))
					{
						iValue = 1000;
						iValue /= (iPathTurns + 1);

						if (iValue > iBestValue)
						{
							CvPlot* endTurnPlot = getPathEndTurnPlot();

							if ( endTurnPlot == pLoopPlot || !exposedToDanger(endTurnPlot, 65) )
							{
								iBestValue = iValue;
								pBestPlot = endTurnPlot;
							}
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}


//	AI_headToBorder is used to cause a unit within our borders to move towards them.  It will
//	prefer borders with players we are at war with, over nborders to neutral, over borders
//	to players we are not at war with
bool	CvUnitAI::AI_moveToBorders()
{
	PROFILE_FUNC();

	CvPlot*	pLoopPlot;
	CvPlot*	pBestPlot = NULL;
	int		iDistance = 1;
	int		iBestValue = 0;
	bool	bValid;

	//	Just intended for units inside our territory to head out
	if ( plot()->getOwnerINLINE() != getOwnerINLINE() )
	{
		return false;
	}

	do
	{
		bValid = false;

		//	Examine the ring of plots iDistance away from us (this is a square)
		for(int iPerimeter = -iDistance; iPerimeter < iDistance; iPerimeter++)
		{
			for( int iSide = 0; iSide < 4; iSide++ )
			{
				int iX = plot()->getX_INLINE();
				int iY = plot()->getY_INLINE();

				switch(iSide)
				{
				case 0:
					//	North side
					iX = iX - iPerimeter;
					iY = iY + iDistance;
					break;
				case 1:
					//	East side
					iX = iX + iDistance;
					iY = iY + iPerimeter;
					break;
				case 2:
					//	South side
					iX = iX + iPerimeter;
					iY = iY - iDistance;
					break;
				case 3:
					//	West side
					iX = iX - iDistance;
					iY = iY - iPerimeter;
					break;
				}

				pLoopPlot = GC.getMapINLINE().plotINLINE(iX,iY);

				if (pLoopPlot != NULL)
				{
					if (AI_plotValid(pLoopPlot) && pLoopPlot->area() == area())
					{
						if ( pLoopPlot->getOwnerINLINE() == getOwnerINLINE() )
						{
							//	Still within our territory somewhere on this ring
							bValid = true;

							int iValue = 0;

							for (int iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
							{
								CvPlot* pAdjacentPlot = plotDirection(iX, iY, ((DirectionTypes)iI));
								if (pAdjacentPlot != NULL)
								{
									if (!pAdjacentPlot->isWater() && pAdjacentPlot->getOwnerINLINE() != getOwnerINLINE())
									{
										iValue += GC.getGameINLINE().getSorenRandNum(300, "AI Move to Border");

										if ( NO_PLAYER == pAdjacentPlot->getOwnerINLINE() )
										{
											iValue += 100;
										}
										else if ( GET_TEAM(getTeam()).isAtWar(pAdjacentPlot->getTeam()) )
										{
											iValue += 200 + GC.getGameINLINE().getSorenRandNum(100, "AI Move to Border2");
										}
									}
								}
							}

							if ( iValue*10 > iBestValue )
							{
								int iPathTurns;

								if ( generatePath(pLoopPlot, 0, true, &iPathTurns) )
								{
									iValue = (iValue*50)/(iPathTurns+5);

									if ( iValue > iBestValue )
									{
										pBestPlot = pLoopPlot;
										iBestValue = iValue;
									}
								}
							}
						}
					}
				}
			}
		}

		if ( iDistance++ > std::max(GC.getMapINLINE().getGridHeight(), GC.getMapINLINE().getGridWidth()) )
		{
			break;
		}
	} while(bValid);

	//	If we're already at the best border plot this mission isn't useful
	if ( pBestPlot != NULL && !atPlot(pBestPlot) )
	{
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}

//AI_patrolBorders relys heavily on the units current facing direction to determine where the next
//move should be. For example, units facing north should not turn around south, or any southerly
//direction (southwest, southeast) to patrol, since that would cause them to move back and forth 
//in a nonsensical manner. Instead, they should appear to be intelligent, and move around 
//the players borders in a circuit, without turning back or leaving the boundries of 
//the cultural borders. This is not in fact the most optimal method of patroling, but it 
//produces results that make sense to the average human, which is the actual goal, since 
//the AI actually never use this function, only automated human units do.
bool CvUnitAI::AI_patrolBorders()
{
	PROFILE_FUNC();
	
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;

	iBestValue = 0;
	pBestPlot = NULL;
	
	int iDX, iDY;

	int iSearchRange = baseMoves();

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			CvPlot* pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (canMoveInto(pLoopPlot, false, false, true, false, false))
				{
					DirectionTypes eNewDirection = estimateDirection(plot(), pLoopPlot);
					iValue = GC.getGameINLINE().getSorenRandNum(10000, "AI Border Patrol");
					if (pLoopPlot->isBorder(true))
					{
						iValue += GC.getGameINLINE().getSorenRandNum(10000, "AI Border Patrol");
					}
					else if (pLoopPlot->isBorder(false))
					{
						iValue += GC.getGameINLINE().getSorenRandNum(5000, "AI Border Patrol");
					}
					//Avoid heading backwards, we want to circuit our borders, if possible.
					if (eNewDirection == getOppositeDirection(getFacingDirection(false)))
					{
						iValue /= 25;
					}
					else if (isAdjacentDirection(getOppositeDirection(getFacingDirection(false)), eNewDirection))
					{
						iValue /= 10;
					}
					if (pLoopPlot->getOwnerINLINE() != getOwnerINLINE())
					{
						if (GET_PLAYER(getOwnerINLINE()).isModderOption(MODDEROPTION_AUTO_PATROL_CAN_LEAVE_BORDERS))
						{
							iValue = -1;
						}
						else
						{
							iValue /= 10;
						}
					}
					if (getDomainType() == DOMAIN_LAND && pLoopPlot->isWater() || getDomainType() == DOMAIN_SEA && !pLoopPlot->isWater())
					{
						iValue /= 10;
					}
					if (iValue > iBestValue)
					{
						iBestValue = iValue;
						pBestPlot = pLoopPlot;
					}
				}
			}
		}
	}
	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}
	
	return false;
}

void CvUnitAI::AI_AutomatedpillageMove()
{
	PROFILE_FUNC();

	if (AI_heal(30, 1))
	{
		return;
	}

	if (plot()->isOwned() && plot()->getOwnerINLINE() != getOwnerINLINE())
	{
		if (AI_AutomatedPillage(40))
		{
			return;
		}

	}
	
	if (AI_pillageRange(3, 11))
	{
		return;
	}

	if (AI_pillageRange(1))
	{
		return;
	}

	if (AI_heal(50, 3))
	{
		return;
	}

	if (!isEnemy(plot()->getTeam()))
	{
		if (AI_heal())
		{
			return;
		}
	}

	if (AI_AutomatedPillage(20))
	{
		return;
	}
	
	if ((area()->getAreaAIType(getTeam()) == AREAAI_OFFENSIVE) || isEnemy(plot()->getTeam()))
	{
		if (AI_pillage(20))
		{
			return;
		}
	}

	if (AI_heal())
	{
		return;
	}

	if (AI_AutomatedPillage(0))
	{
		return;
	}
	
	if (AI_retreatToCity())
	{
		return;
	}

	if (AI_safety())
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

void CvUnitAI::AI_autoAirStrike()
{
	PROFILE_FUNC();

	CvCity* pCity = plot()->getPlotCity();
	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
	CvArea* pArea = area();
	
	//Heal
	if( getDamage() > 0 )
	{
		if (((100*currHitPoints()) / maxHitPoints()) < 50)
		{
			getGroup()->pushMission(MISSION_SKIP);
			return;
		}
	}

	// Attack the invaders!
	if (AI_defendBaseAirStrike())
	{
		return;
	}
	
	//Attack enemies in range
	if (AI_defensiveAirStrike())
	{
		return;
	}

	//Attack anyone
	if (AI_airStrike())
	{
		return;
	}

	if (kPlayer.isModderOption(MODDEROPTION_AUTO_AIR_CAN_REBASE))
	{
		// If no targets, no sense staying in risky place
		if (AI_airOffensiveCity())
		{
			return;
		}

		if( canAirDefend() )
		{
			if (AI_airDefensiveCity())
			{
				return;
			}
		}

		if( healTurns(plot()) > 1 )
		{
			// If very damaged, no sense staying in risky place
			if (AI_airOffensiveCity())
			{
				return;
			}

			if( canAirDefend() )
			{
				if (AI_airDefensiveCity())
				{
					return;
				}
			}
		}
	}

	if (kPlayer.isModderOption(MODDEROPTION_AUTO_AIR_CAN_DEFEND))
	{
		int iAttackValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_ATTACK_AIR, pArea);
		int iDefenseValue = kPlayer.AI_unitValue(getUnitType(), UNITAI_DEFENSE_AIR, pArea);
		if (iDefenseValue > iAttackValue)
		{
			if (kPlayer.AI_bestAreaUnitAIValue(UNITAI_ATTACK_AIR, pArea) > iAttackValue)
			{
				AI_setUnitAIType(UNITAI_DEFENSE_AIR);
				getGroup()->pushMission(MISSION_SKIP);
				return;	
			}
		}
	}
	
	
	bool bDefensive = false;
	if( pArea != NULL )
	{
		bDefensive = pArea->getAreaAIType(getTeam()) == AREAAI_DEFENSIVE;
	}
	if (kPlayer.isModderOption(MODDEROPTION_AUTO_AIR_CAN_REBASE) && kPlayer.isModderOption(MODDEROPTION_AUTO_AIR_CAN_DEFEND))
	{
		if (GC.getGameINLINE().getSorenRandNum(bDefensive ? 3 : 6, "AI Air Attack Move") == 0)
		{
			if( AI_defensiveAirStrike() )
			{
				return;
			}
		}
	}

	if (kPlayer.isModderOption(MODDEROPTION_AUTO_AIR_CAN_REBASE))
	{
		if (GC.getGameINLINE().getSorenRandNum(4, "AI Air Attack Move") == 0)
		{
			// only moves unit in a fort
			if (AI_travelToUpgradeCity())
			{
				return;
			}
		}
	}

	// Support ground attacks
	if (canAirBomb(NULL))
	{
		if (AI_airBombDefenses())
		{
			return;
		}

		if (AI_airBombPlots())
		{
			return;
		}
	}

	if (AI_airStrike())
	{
		return;
	}

	if (AI_airBombCities())
	{
		return;
	}
	
	if (canAirDefend() && kPlayer.isModderOption(MODDEROPTION_AUTO_AIR_CAN_DEFEND))
	{
		if( bDefensive || GC.getGameINLINE().getSorenRandNum(2, "AI Air Attack Move") == 0 )
		{
			getGroup()->pushMission(MISSION_AIRPATROL);
			return;
		}
	}
	
	if (canRecon(plot()))
	{
		if (AI_exploreAir())
		{
			return;
		}
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

// Returns true if a mission was pushed...
bool CvUnitAI::AI_airBombCities()
{
	//PROFILE_FUNC();

	CvUnit* pDefender;
	CvUnit* pInterceptor;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iDamage;
	int iPotentialAttackers;
	int iInterceptProb;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iSearchRange = airRange();

	iBestValue = (isSuicide() && m_pUnitInfo->getProductionCost() > 0) ? (5 * m_pUnitInfo->getProductionCost()) / 6 : 0;
	pBestPlot = NULL;

	for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
	{
		for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
		{
			pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (canMoveInto(pLoopPlot, true))
				{
					iValue = 0;
					iPotentialAttackers = pLoopPlot->getNumVisibleEnemyDefenders(this);

					if (iPotentialAttackers > 0)
					{
						pDefender = pLoopPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

						FAssert(pDefender != NULL);
						FAssert(pDefender->canDefend());

						// XXX factor in air defenses...

						iDamage = airCombatDamage(pDefender);

						iValue = std::max(0, (std::min((pDefender->getDamage() + iDamage), airCombatLimit()) - pDefender->getDamage()));

						iValue += ((((iDamage * collateralDamage()) / 100) * std::min((pLoopPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits())) / 2);

						iValue *= (3 + iPotentialAttackers);
						iValue /= 4;

						pInterceptor = bestInterceptor(pLoopPlot);

						if (pInterceptor != NULL)
						{
							iInterceptProb = isSuicide() ? 100 : pInterceptor->currInterceptionProbability();

							iInterceptProb *= std::max(0, (100 - evasionProbability()));
							iInterceptProb /= 100;

							iValue *= std::max(0, 100 - iInterceptProb / 2);
							iValue /= 100;
						}
						
						if (pLoopPlot->isWater())
						{
							iValue *= 2;
						}
						if (pLoopPlot->isCity())
						{
							iValue *= 2;
						}

						if (iValue > iBestValue)
						{
							iBestValue = iValue;
							pBestPlot = pLoopPlot;
							FAssert(!atPlot(pBestPlot));
						}
					}
				}
			}
		}
	}

	if (pBestPlot != NULL)
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}

	return false;
}


void CvUnitAI::AI_shadowMove()
{
	PROFILE_FUNC();

	CvUnit* pTarget = getShadowUnit();
	FAssertMsg(pTarget != NULL, "Should be Shading a Unit!");
	
	if (AI_protectTarget(pTarget))
	{
		return;
	}
	
	if (AI_moveToTarget(pTarget))
	{
		return;
	}

	getGroup()->pushMission(MISSION_SKIP);
	return;
}

bool CvUnitAI::AI_moveToTarget(CvUnit* pTarget)
{
	PROFILE_FUNC();
	
	int iPathTurns;
	
	if (atPlot(pTarget->plot()))
	{
		return false;
	}
	
	if (generatePath(pTarget->plot(), 0, true, &iPathTurns))
	{
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, getPathEndTurnPlot()->getX_INLINE(), getPathEndTurnPlot()->getY_INLINE());
	}
	
	return false;
}

bool CvUnitAI::AI_protectTarget(CvUnit* pTarget)
{
	PROFILE_FUNC();

	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iSearchRange;
	int iPathTurns;
	int iValue;
	int iBestValue;
	int iDX, iDY;

	iSearchRange = baseMoves();

	iBestValue = 0;
	pBestPlot = NULL;
	
	int iDanger = GET_PLAYER(getOwnerINLINE()).AI_getPlotDanger(pTarget->plot(), 1, false);
	
	//No Danger
	if (iDanger == 0)
	{
		return false;
	}
	
	//Lots of Danger, Move Ontop of Target to protect it
	else if (iDanger > getGroup()->getNumUnits())
	{
		if (generatePath(pTarget->plot(), 0, true, &iPathTurns))
		{
			getGroup()->pushMission(MISSION_MOVE_TO, getPathEndTurnPlot()->getX_INLINE(), getPathEndTurnPlot()->getY_INLINE());
			return true;
		}
	}

	//Only minimal enemy targets, move to kill them if possible
	else
	{
		for (iDX = -(iSearchRange); iDX <= iSearchRange; iDX++)
		{
			for (iDY = -(iSearchRange); iDY <= iSearchRange; iDY++)
			{
				pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);

				if (pLoopPlot != NULL)
				{
					if (AI_plotValid(pLoopPlot))
					{
						if (pLoopPlot->isVisible(getTeam(),false) && pLoopPlot->isVisibleEnemyUnit(this))
						{
							if (!atPlot(pLoopPlot) && canMoveInto(pLoopPlot, true) && generatePath(pLoopPlot, 0, true, &iPathTurns, 1))
							{
								if (pLoopPlot->getNumVisibleEnemyDefenders(this) <= getGroup()->getNumUnits())
								{
									if (pLoopPlot->getNumVisibleAdjacentEnemyDefenders(this) <= ((getGroup()->getNumUnits() * 3) / 2))
									{
										iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

										if (iValue >= AI_finalOddsThreshold(pLoopPlot, 65))
										{
											if (iValue > iBestValue)
											{
												iBestValue = iValue;
												pBestPlot = getPathEndTurnPlot();
												FAssert(!atPlot(pBestPlot));
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
	
	//Not possible to kill enemies, retreat to target
	if (pBestPlot == NULL)
	{
		if (atPlot(pTarget->plot()))
		{
			getGroup()->pushMission(MISSION_SKIP);
			return true;
		}
		else if (generatePath(pTarget->plot(), 0, true, &iPathTurns))
		{
			return getGroup()->pushMissionInternal(MISSION_MOVE_TO, getPathEndTurnPlot()->getX_INLINE(), getPathEndTurnPlot()->getY_INLINE());
		}
	}
	else
	{
		FAssert(!atPlot(pBestPlot));
		return getGroup()->pushMissionInternal(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_DIRECT_ATTACK, false, false);
	}

	return false;
}

bool CvUnitAI::AI_joinMilitaryCity()
{
	PROFILE_FUNC();

	CvCity* pLoopCity;
	CvPlot* pBestPlot;
	SpecialistTypes eBestSpecialist;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;
	int iCount;

	iBestValue = 0;
	pBestPlot = NULL;
	eBestSpecialist = NO_SPECIALIST;
	iCount = 0;

	for (pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
	{
		if ((pLoopCity->area() == area()) && AI_plotValid(pLoopCity->plot()))
		{
			if (pLoopCity->AI_isMilitaryProductionCity())
			{
				if (!(pLoopCity->plot()->isVisibleEnemyUnit(this)))
				{
					if (generatePath(pLoopCity->plot(), MOVE_SAFE_TERRITORY, true))
					{
						if ( !(GET_PLAYER(getOwnerINLINE()).AI_getAnyPlotDanger(pLoopCity->plot(), 2)) )
						{
							for (iI = 0; iI < GC.getNumSpecialistInfos(); iI++)
							{
								if (canJoin(pLoopCity->plot(), ((SpecialistTypes)iI)))
								{
									iValue = pLoopCity->AI_specialistValue(((SpecialistTypes)iI), pLoopCity->AI_avoidGrowth(), false);
									if (iValue > iBestValue)
									{
										iBestValue = iValue;
										pBestPlot = getPathEndTurnPlot();
										eBestSpecialist = ((SpecialistTypes)iI);
									}
								}
							}
						}
					}
				}
			}
		}
	}

	if ((pBestPlot != NULL) && (eBestSpecialist != NO_SPECIALIST))
	{
		if (atPlot(pBestPlot))
		{
			getGroup()->pushMission(MISSION_JOIN, eBestSpecialist);
			return true;
		}
		else
		{
			FAssert(!atPlot(pBestPlot));
			getGroup()->pushMission(MISSION_MOVE_TO, pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE(), MOVE_SAFE_TERRITORY);
			return true;
		}
	}

	return false;
}

bool CvUnitAI::AI_isPlotWellDefended(CvPlot* pPlot, bool bIncludeAdjacent, int iOddsOfDefeat)
{
	PROFILE_FUNC();

	int iOurOffense = GET_TEAM(getTeam()).AI_getOurPlotStrength(plot(),(bIncludeAdjacent ? 1 : 0),true,false,true);
	int iEnemyDefense = GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pPlot,(bIncludeAdjacent ? 1 : 0),true,false);
	iOurOffense *= iOddsOfDefeat;
	iEnemyDefense *= 100;
	return iOurOffense < iEnemyDefense;
}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/

void CvUnitAI::AI_flushValueCache()
{
	m_iGenericValue = -1;
}

//	Assess the value of a unit without the context of any specific battle/scenario
//	This is its max strength, modified by promotions
int	CvUnitAI::AI_genericUnitValueTimes100(UnitValueFlags eFlags) const
{
	PROFILE_FUNC();

	if ( m_iGenericValue == -1 || m_eGenericValueFlagsCached != eFlags )
	{
		int	iResult = 100*baseCombatStr();

		for(int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
		{
			if ( isHasPromotion((PromotionTypes)iI) )
			{
				CvPromotionInfo&	kPromotion = GC.getPromotionInfo((PromotionTypes)iI);
				bool				bPromotionHasAccountedValue = false;

				//	Generic strength multiplier
				if ( kPromotion.getCombatPercent() != 0 )
				{
					iResult = (iResult * (100+kPromotion.getCombatPercent()))/100;

					bPromotionHasAccountedValue |= (kPromotion.getCombatPercent() > 0);
				}

				//	Unit combat modifiers
				for(int iJ = 0; iJ < GC.getNumUnitCombatInfos(); iJ++)
				{
					if ( kPromotion.getUnitCombatModifierPercent((UnitCombatTypes)iJ) != 0 )
					{
						//	Future - make this adaptive to the area's known enemy units
						//	Note - the scaling factor of 5 (implicit in the 500) is because
						//	although there are actually 40 or so unit combat types only a small
						//	faraction are in wide use or appear in promotions in practice.  Once this
						//	is normalized for acvtual occurance of units that fudge factor won't be needed
						int	iUnitCombatWeight = 500/GC.getNumUnitCombatInfos();

						iResult = (iResult * (100+(iUnitCombatWeight*kPromotion.getUnitCombatModifierPercent((UnitCombatTypes)iJ))/100))/100;

						bPromotionHasAccountedValue |= (kPromotion.getUnitCombatModifierPercent((UnitCombatTypes)iJ) > 0);
					}
				}

				//	First strikes
				if ( kPromotion.getFirstStrikesChange() != 0 )
				{
					int iFirstStrikesWeight = 15;

					iResult = (iResult * (100 + iFirstStrikesWeight*kPromotion.getFirstStrikesChange()))/100;

					bPromotionHasAccountedValue |= (kPromotion.getFirstStrikesChange() > 0);
				}

				//	Tile and adjacent tile healing are considred with any flags
				if ( kPromotion.getSameTileHealChange() != 0 )
				{
					int iSameTileHealWeight = 75;

					iResult = (iResult * (100 + (iSameTileHealWeight*kPromotion.getSameTileHealChange())/100))/100;

					bPromotionHasAccountedValue |= (kPromotion.getSameTileHealChange() > 0);
				}
				if ( kPromotion.getAdjacentTileHealChange() != 0 )
				{
					int iAdjacentTileHealWeight = 200;

					iResult = (iResult * (100 + (iAdjacentTileHealWeight*kPromotion.getAdjacentTileHealChange())/100))/100;

					bPromotionHasAccountedValue |= (kPromotion.getAdjacentTileHealChange() > 0);
				}

				if ( (eFlags & UNITVALUE_FLAGS_DEFENSIVE) != 0 )
				{
					//	Terrain defense
					for(int iJ = 0; iJ < GC.getNumTerrainInfos(); iJ++)
					{
						if ( kPromotion.getTerrainDefensePercent((TerrainTypes)iJ) != 0 ||
							 kPromotion.getIgnoreTerrainDamage() == iJ )
						{
							int iNumRevealedAreaTiles = area()->getNumRevealedTiles(getTeam());
							int	iNumRevealedAreaThisTerrain = area()->getNumRevealedTerrainTiles(getTeam(), (TerrainTypes)iJ);

							//	Note - used 1000 multiplier here for better granularity because there are
							//	a lot of terrain types.  We multiply the actual ratio by 2 because in practise the AI will
							//	deploy the units to appropriate terrains/features when it can so the the effective value is
							//	higher than the raw proportion would apply
							int	iTerrainWeight = (2*1000*iNumRevealedAreaThisTerrain)/iNumRevealedAreaTiles;

							iResult = (iResult * (10000+(kPromotion.getTerrainDefensePercent((TerrainTypes)iJ) * iTerrainWeight)/10))/10000;
						}
					}
					//	Feature defense
					for(int iJ = 0; iJ < GC.getNumFeatureInfos(); iJ++)
					{
						if ( kPromotion.getFeatureDefensePercent((FeatureTypes)iJ) != 0 )
						{
							int iNumRevealedAreaTiles = area()->getNumRevealedTiles(getTeam());
							int	iNumRevealedAreaThisFeature = area()->getNumRevealedFeatureTiles(getTeam(), (FeatureTypes)iJ);

							//	Note - used 1000 multiplier here for better granularity because there are
							//	a lot of feature types.  We multiply the actual ratio by 2 because in practise the AI will
							//	deploy the units to appropriate terrains/features wehn it can so the the effective value is
							//	higher than the raw proportion would apply
							int	iFeatureWeight = (2*1000*iNumRevealedAreaThisFeature)/iNumRevealedAreaTiles;

							iResult = (iResult * (10000+(kPromotion.getFeatureDefensePercent((FeatureTypes)iJ) * iFeatureWeight)/10))/10000;

							bPromotionHasAccountedValue |= (kPromotion.getFeatureDefensePercent((FeatureTypes)iJ) > 0);
						}
					}
					//	Hills defense
					if ( kPromotion.getHillsDefensePercent() != 0 )
					{
						int iHillsWeight = 30;	//	Crudely assume 30% hills for now

						iResult = (iResult * (100+(kPromotion.getHillsDefensePercent() * iHillsWeight)/100))/100;

						bPromotionHasAccountedValue |= (kPromotion.getHillsDefensePercent() > 0);
					}
					//	City defense
					if( kPromotion.getCityDefensePercent() != 0 )
					{
						//	Always value city defence as half since units with it are often going to be stationed in cities
						iResult = (iResult * (100+kPromotion.getCityDefensePercent()/2))/100;

						bPromotionHasAccountedValue |= (kPromotion.getCityDefensePercent() > 0);
					}

					//	First strike immunity
					if ( kPromotion.isImmuneToFirstStrikes() )
					{
						int		iFirstStrikeWeight = 120;	//	Future - make this adaptive to known enemy units

						iResult = (iResult * iFirstStrikeWeight)/100;

						bPromotionHasAccountedValue = true;
					}

					//	Consider healing as part of defense
					if ( kPromotion.isAlwaysHeal() )
					{
						int		iAlwaysHealWeight = 140;

						iResult = (iResult * iAlwaysHealWeight)/100;

						bPromotionHasAccountedValue = true;
					}

					//	For defense consider extra healing in friendly terrioty
					if ( kPromotion.getFriendlyHealChange() != 0 )
					{
						int		iHealWeight = 25;

						iResult = (iResult * (1000+(kPromotion.getFriendlyHealChange() * iHealWeight)/1000))/1000;

						bPromotionHasAccountedValue |= (kPromotion.getFriendlyHealChange() > 0);
					}
				}

				if ( (eFlags & UNITVALUE_FLAGS_OFFENSIVE) != 0 )
				{
					//	Terrain attack
					for(int iJ = 0; iJ < GC.getNumTerrainInfos(); iJ++)
					{
						if ( kPromotion.getTerrainAttackPercent((TerrainTypes)iJ) != 0 ||
							 kPromotion.getIgnoreTerrainDamage() == iJ )
						{
							int iNumRevealedAreaTiles = area()->getNumRevealedTiles(getTeam());
							int	iNumRevealedAreaThisTerrain = area()->getNumRevealedTerrainTiles(getTeam(), (TerrainTypes)iJ);

							//	Note - used 1000 multiplier here for better granularity because there are
							//	a lot of terrain types.  We multiply the actual ratio by 2 because in practise the AI will
							//	deploy the units to appropriate terrains/features when it can so the the effective value is
							//	higher than the raw proportion would apply
							int	iTerrainWeight = (2*1000*iNumRevealedAreaThisTerrain)/iNumRevealedAreaTiles;

							iResult = (iResult * (10000+(kPromotion.getTerrainAttackPercent((TerrainTypes)iJ) * iTerrainWeight)/10))/10000;

							bPromotionHasAccountedValue |= (kPromotion.getTerrainAttackPercent((TerrainTypes)iJ) > 0);
						}
					}
					//	Feature attack
					for(int iJ = 0; iJ < GC.getNumFeatureInfos(); iJ++)
					{
						if ( kPromotion.getFeatureAttackPercent((FeatureTypes)iJ) != 0 )
						{
							int iNumRevealedAreaTiles = area()->getNumRevealedTiles(getTeam());
							int	iNumRevealedAreaThisFeature = area()->getNumRevealedFeatureTiles(getTeam(), (FeatureTypes)iJ);

							//	Note - used 1000 multiplier here for better granularity because there are
							//	a lot of feature types.  We multiply the actual ratio by 2 because in practise the AI will
							//	deploy the units to appropriate terrains/features wehn it can so the the effective value is
							//	higher than the raw proportion would apply
							int	iFeatureWeight = (2*1000*iNumRevealedAreaThisFeature)/iNumRevealedAreaTiles;

							iResult = (iResult * (10000+(kPromotion.getFeatureAttackPercent((FeatureTypes)iJ) * iFeatureWeight)/10))/10000;

							bPromotionHasAccountedValue |= (kPromotion.getFeatureAttackPercent((FeatureTypes)iJ) > 0);
						}
					}
					//	Hills attack
					if ( kPromotion.getHillsAttackPercent() != 0 )
					{
						int iHillsWeight = 30;	//	Crudely assume 30% hills for now

						iResult = (iResult * (100+(kPromotion.getHillsAttackPercent() * iHillsWeight)/100))/100;

						bPromotionHasAccountedValue |= (kPromotion.getHillsAttackPercent() > 0);
					}
					//	City attack
					if( kPromotion.getCityAttackPercent() != 0 )
					{
						//	Always value city attack as half since units with it are often going to be used in attacks
						iResult = (iResult * (100+kPromotion.getCityAttackPercent()/2))/100;

						bPromotionHasAccountedValue |= (kPromotion.getCityAttackPercent() > 0);
					}

					//	For attack consider extra healing in neutral and enemy territory
					if ( kPromotion.getNeutralHealChange() != 0 )
					{
						int		iNeutralHealWeight = 20;

						iResult = (iResult * (1000+(kPromotion.getNeutralHealChange() * iNeutralHealWeight)/10))/1000;

						bPromotionHasAccountedValue |= (kPromotion.getNeutralHealChange() > 0);
					}
					if ( kPromotion.getEnemyHealChange() != 0 )
					{
						int		iEnemyHealWeight = 30;

						iResult = (iResult * (1000+(kPromotion.getEnemyHealChange() * iEnemyHealWeight)/10))/1000;

						bPromotionHasAccountedValue |= (kPromotion.getEnemyHealChange() > 0);
					}
				}

				if ( (eFlags & UNITVALUE_FLAGS_UTILITY) != 0 )
				{
				}

				if ( (eFlags & UNITVALUE_FLAGS_ALL) == UNITVALUE_FLAGS_ALL && !bPromotionHasAccountedValue )
				{
					//	We don't know what this promotion is for but it must be worth something
					int	iUnknownPromotionWeight = 110;

					iResult = (iResult * iUnknownPromotionWeight)/100;
				}
			}
		}

		m_iGenericValue = iResult;
		m_eGenericValueFlagsCached = eFlags;
	}

	return m_iGenericValue;
}

bool CvUnitAI::AI_approximatePath(CvPlot* pToPlot, int iFlags, int* piPathTurns) const
{
	PROFILE_FUNC();

#define CLOSE_THRESHOLD 10
	CvPlot*	start = plot();
	int	iStepPathLen = GC.getMapINLINE().calculatePathDistance(start, pToPlot);

	OutputDebugString(CvString::format("Approx path from (%d,%d) to (%d,%d), step pathLen: %d\n",start->getX_INLINE(),start->getY_INLINE(),pToPlot->getX_INLINE(), pToPlot->getY_INLINE(), iStepPathLen).c_str());

	if ( iStepPathLen == -1 )
	{
		OutputDebugString("Not pathable\n");
		return false;
	}
	else if ( iStepPathLen < CLOSE_THRESHOLD )
	{
		PROFILE("AI_approximatePath.Close");
		bool bResult = generatePath(pToPlot, iFlags, true, piPathTurns);

		if ( bResult )
		{
			OutputDebugString(CvString::format("Actual close path evaluation yielded length of %d\n", *piPathTurns).c_str());
		}
		else
		{
			OutputDebugString("Not pathable on close path verification!!\n");
		}

		return bResult;
	}
	else
	{
		PROFILE("AI_approximatePath.Distant");
		//	Find actual path length of a starting subpath of the step path to
		//	use to generate a normalization factor to estimate an actual cost
		FAStarNode* pNode = gDLL->getFAStarIFace()->GetLastNode(&GC.getStepFinder());

		while( pNode->m_iData1 >= CLOSE_THRESHOLD )
		{
			pNode = pNode->m_pParent;
		}

		//	Make sure we can path this stack to here, else shrink it back until we can
		FAStarNode* pCandidateSubPathEndNode = pNode;

		while( pNode->m_pParent != NULL )
		{
			if ( !canMoveInto( GC.getMapINLINE().plotINLINE(pNode->m_iX,pNode->m_iY)) )
			{
				pCandidateSubPathEndNode = pNode->m_pParent;
			}

			pNode = pNode->m_pParent;
		}

		CvPlot* pSubPathTerminus = GC.getMapINLINE().plotINLINE(pCandidateSubPathEndNode->m_iX, pCandidateSubPathEndNode->m_iY);
		int iSubPathTurns;

		{
			PROFILE("AI_approximatePath.DistantSubPathCalc");
			if ( !generatePath(pSubPathTerminus, iFlags, true, &iSubPathTurns) )
			{
				OutputDebugString("Unpathable sub-path found!!\n");

				//	This should never happen - if it does something has goen wrong - just evaluate the
				//	entire path
				return generatePath(pToPlot, iFlags, true, piPathTurns);
			}

			//	Now normalise the step path length by the ratio of the subpath step length to its actual length
			*piPathTurns = (iStepPathLen*iSubPathTurns)/std::max(1,pCandidateSubPathEndNode->m_iData1);

			OutputDebugString(CvString::format("Sub path evaluation yielded length of %d vs %d, normalising total to %d\n", iSubPathTurns, pCandidateSubPathEndNode->m_iData1, *piPathTurns).c_str());
		}
	}

	return true;
}

bool CvUnitAI::AI_isCityGarrison(const CvCity* pCity) const
{
	return (m_iGarrisonCity != -1 && m_iGarrisonCity == pCity->getID());
}
	
void CvUnitAI::AI_setAsGarrison(const CvCity* pCity)
{
	int iGarrisonCity = (pCity == NULL ? -1 : pCity->getID());

	m_iAffirmedGarrisonCity = iGarrisonCity;

	if ( iGarrisonCity != m_iGarrisonCity )
	{
		if ( pCity == NULL )
		{
			pCity = GET_PLAYER(getOwnerINLINE()).getCity(m_iGarrisonCity);
		}

		m_iGarrisonCity = iGarrisonCity;

		if( gUnitLogLevel >= 3 )
		{
			if ( iGarrisonCity == -1 )
			{
				if ( pCity != NULL )
				{
					logBBAI("    Unit %S (group %d with %d units) for player %d (%S) at (%d,%d) leaves garrison for city %S\n",
							getUnitInfo().getDescription(),
							getGroup()->getID(),
							getGroup()->getNumUnits(),
							getOwner(),
							GET_PLAYER(getOwner()).getCivilizationDescription(0),
							plot()->getX_INLINE(),
							plot()->getY_INLINE(),
							pCity->getName().GetCString());
				}
			}
			else
			{
				FAssert(pCity != NULL);
				logBBAI("    Unit %S (group %d with %d units) for player %d (%S) at (%d,%d) joins garrison for city %S\n",
						getUnitInfo().getDescription(),
						getGroup()->getID(),
						getGroup()->getNumUnits(),
						getOwner(),
						GET_PLAYER(getOwner()).getCivilizationDescription(0),
						plot()->getX_INLINE(),
						plot()->getY_INLINE(),
						pCity->getName().GetCString());
			}
		}
	}
}


void unitSourcesValueToCity(CvGameObject* pObject, CvPropertyManipulators* pMani, const CvUnit* pUnit, const CvCityAI* pCity, int* iValue)
{
	if ( pCity == NULL )
	{
		pCity = static_cast<CvCityAI*>(GET_PLAYER(pUnit->getOwnerINLINE()).getCapitalCity());
	}

	if ( pCity != NULL )
	{
		int iNum = pMani->getNumSources();

		for (int i=0; i<iNum; i++)
		{
			CvPropertySource* pSource = pMani->getSource(i);

			//	Sources that deliver to the city or the plot are both considered since the city plot diffuses
			//	to the city for most properties anyway
			if (pSource->getType() == PROPERTYSOURCE_CONSTANT &&
				(pSource->getObjectType() == GAMEOBJECT_CITY || pSource->getObjectType() == GAMEOBJECT_PLOT))
			{
				PropertyTypes eProperty = pSource->getProperty();
				int iCurrentSourceSize = pCity->getTotalBuildingSourcedProperty(eProperty) + pCity->getTotalUnitSourcedProperty(eProperty) + pCity->getPropertyNonBuildingSource(eProperty);
				int iNewSourceSize = iCurrentSourceSize + ((CvPropertySourceConstant*)pSource)->getAmountPerTurn(pCity->getGameObjectConst());
				int iDecayPercent = pCity->getPropertyDecay(eProperty);

				//	Steady state occurs at a level where the decay removes as much per turn as the sources add
				//	Decay can be 0 if the current level is below the threshold at which decay cuts in, so for the
				//	purposes of calculation just treat this as very slow decay
				int	iCurrentSteadyStateLevel = (100*iCurrentSourceSize)/std::max(1,iDecayPercent);
				int	iNewSteadyStateLevel = (100*iNewSourceSize)/std::max(1,iDecayPercent);

				*iValue += pCity->getPropertySourceValue(eProperty,
														 iNewSteadyStateLevel - iCurrentSteadyStateLevel)/100;
			}
		}
	}
}

//	Find the total beneficial bnet value to a given city of this unit's property sources
int CvUnitAI::AI_beneficialPropertyValueToCity(CvCity* pCity) const
{
	int iValue = 0;

	((CvUnitAI*)this)->getGameObject()->foreachManipulator(boost::bind(unitSourcesValueToCity, _1, _2, this, static_cast<const CvCityAI*>(pCity), &iValue));

	return iValue;
}

//	Set an override to the group head priority for this unit, to allow a unit that
//	would not nomally lead a stack to do so - priority will be preserved when other groups
//	joing one lead by a unit with an override, but reset if we join another group
void CvUnitAI::AI_setLeaderPriority(int iPriority)	//	 -1 means reset to default
{
	m_iGroupLeadOverride = iPriority;
}