CvPlot* CvArmyAI::DetectNearbyEnemy(PlayerTypes eEnemy, bool bNaval)
{
	UnitHandle pUnit = GetFirstUnit();
	while(pUnit)
	{
		for(int iDirectionLoop = 0; iDirectionLoop < NUM_DIRECTION_TYPES; ++iDirectionLoop)
		{
			CvPlot* pAdjacentPlot = plotDirection(pUnit->getX(), pUnit->getY(), ((DirectionTypes)iDirectionLoop));
			if(pAdjacentPlot != NULL && pAdjacentPlot->isWater()==bNaval && pAdjacentPlot->getOwner() == eEnemy)
			{
				UnitHandle pOtherUnit = pAdjacentPlot->getBestDefender(eEnemy);
				if(pOtherUnit)
				{
					if(GC.getLogging() && GC.getAILogging())
					{
						CvString strMsg;
						strMsg.Format("Ran into enemy unit during attack (x=%d y=%d). Need to declare war to continue!", pAdjacentPlot->getX(), pAdjacentPlot->getY());
						GET_PLAYER(m_eOwner).getAIOperation(m_iOperationID)->LogOperationSpecialMessage(strMsg);
					}

					return pAdjacentPlot;
				}
			}
		}
		pUnit = GetNextUnit();
	}

	return NULL;
}
/// Find first unit who is sitting in this domain
UnitHandle CvArmyAI::GetFirstUnitInDomain(DomainTypes eDomain)
{
	UnitHandle pUnit, pCurrentUnit;

	pCurrentUnit = GetFirstUnit();
	while(pCurrentUnit)
	{
		if(pCurrentUnit->plot()->isWater() && eDomain == DOMAIN_SEA || !pCurrentUnit->plot()->isWater() && eDomain == DOMAIN_LAND)
		{
			return pCurrentUnit;
		}
		pCurrentUnit = GetNextUnit();
	}

	return pUnit;
}
/// Everyone in the water now?
bool CvArmyAI::AreAllInWater()
{
	UnitHandle pUnit;

	pUnit = GetFirstUnit();
	while(pUnit)
	{
		if(!pUnit->plot()->isWater())
		{
			return false;
		}
		pUnit = GetNextUnit();
	}

	return true;
}
/// Return distance from this plot of unit in army farthest away
int CvArmyAI::GetFurthestUnitDistance(CvPlot* pPlot)
{
	int iLargestDistance = 0;
	CvUnit* pUnit = GetFirstUnit();

	while(pUnit)
	{
		int iNewDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY());
		if(iNewDistance > iLargestDistance)
		{
			iLargestDistance = iNewDistance;
		}
		pUnit = GetNextUnit(pUnit);
	}
	return iLargestDistance;
}
Beispiel #5
0
// Gather up all units for this team
int GroundTaskingManagerClass::CollectGroundAssets (int to_collect)
{
	Unit			u,pu;
	int				count=0,objListBuilt=0;

	// Create the unit lists
	VuListIterator	myit(AllParentList);
	u = GetFirstUnit(&myit);
	while (u)
	{
		if (u->GetTeam() == owner && u->GetDomain() == DOMAIN_LAND && !u->Scripted())
		{
			// We've got at least one unit to assign - build our objective lists
			if (!objListBuilt)
			{
				Setup();
				BuildObjectiveLists(to_collect);
				objListBuilt = 1;
			}
			u->RallyUnit(MIN_TASK_GROUND);
			u->UpdateParentStatistics();
			// We want to order support battalions individually.
			if (!u->Real() && FindUnitSupportRole(u))
			{
				pu = u;
				u = pu->GetFirstUnitElement();
				while (u)
				{
					AddToLists(u, to_collect);
					count++;
					u = pu->GetNextUnitElement();
				}
			}
			else
			{
				AddToLists(u, to_collect);
				count++;
			}
		}
		u = GetNextUnit(&myit);
	}
	return count;
}
Beispiel #6
0
void GroundTaskingManagerClass::RequestEngineer (Objective o, int division)
{
	Unit				u;
	o->SetNeedRepair(1);

	VuListIterator	myit(AllParentList);
	u = GetFirstUnit(&myit);
	while (u)
	{
		if (u->GetTeam() == owner && u->GetDomain() == DOMAIN_LAND && 
						u->GetUnitNormalRole() == GRO_ENGINEER && u->GetUnitDivision() == division && u->GetUnitOrders() != GORD_REPAIR)
		{
			u->SetUnitOrders(GORD_REPAIR,o->Id());
			return;
		}
		u = GetNextUnit(&myit);
	}
	// Find the best _free_ engineer to send to this location
}
/// Can all units in this army move on ocean?
bool CvArmyAI::IsAllOceanGoing()
{
	CvUnit* pUnit = GetFirstUnit();
	while(pUnit)
	{
		if(pUnit->getDomainType() != DOMAIN_SEA && !pUnit->IsHasEmbarkAbility())
		{
			return false;
		}

		// If can move over ocean, not a coastal vessel
		if(pUnit->isTerrainImpassable(TERRAIN_OCEAN))
		{
			return false;
		}

		pUnit = GetNextUnit(pUnit);
	}

	return true;
}
/// Find average speed of units in army
int CvArmyAI::GetMovementRate()
{
	int iMovementAverage = 2;   // A reasonable default
	int iNumUnits = 0;
	int iTotalMovementAllowance = 0;
	UnitHandle pUnit;

	pUnit = GetFirstUnit();
	while(pUnit)
	{
		iNumUnits++;
		iTotalMovementAllowance += pUnit->baseMoves();
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		iMovementAverage = (iTotalMovementAllowance + (iNumUnits / 2)) / iNumUnits;
	}

	return iMovementAverage;
}
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(float* pfVarX, float* pfVarY)
{
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;

	UnitHandle pUnit = GetFirstUnit();
	if (!pUnit)
		return NULL;

	int iTotalX2 = 0;
	int iTotalY2 = 0;
	int iWorldWidth = GC.getMap().getGridWidth();
	int iWorldHeight = GC.getMap().getGridHeight();

	//the first unit is our reference ...
	int iRefX = pUnit->getX();
	int iRefY = pUnit->getY();
	iNumUnits++;
	pUnit = GetNextUnit();

	while(pUnit)
	{
		int iDX = pUnit->getX() - iRefX;
		int iDY = pUnit->getY() - iRefY;

		if (GC.getMap().isWrapX())
		{
			if( iDX > +(iWorldWidth / 2))
				iDX -= iWorldWidth;
			if( iDX < -(iWorldWidth / 2))
				iDX += iWorldWidth;
		}
		if (GC.getMap().isWrapY())
		{
			if( iDY > +(iWorldHeight / 2))
				iDY -= iWorldHeight;
			if( iDY < -(iWorldHeight / 2))
				iDY += iWorldHeight;
		}

		iTotalX += iDX;
		iTotalY += iDY;
		iTotalX2 += iDX*iDX;
		iTotalY2 += iDY*iDY;
		iNumUnits++;

		pUnit = GetNextUnit();
	}

	if (iNumUnits==0)
		return NULL;

	//this is for debugging
	float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits);
	float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits);

	//finally, compute average (with rounding)
	int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX;
	int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY;

	if (fVarX > 64 || fVarY > 64)
	{
		CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY);
		OutputDebugString( msg.c_str() );
	}

	//this handles wrapped coordinates
	CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY);

	if (!pCOM)
		return NULL;

	if (pfVarX)
		*pfVarX = fVarX;
	if (pfVarY)
		*pfVarY = fVarY;

	//don't return it directly but use the plot of the closest unit
	pUnit = GetFirstUnit();
	std::vector<SPlotWithScore> vPlots;
	while (pUnit)
	{
		if (pUnit->plot()->getDomain()==GetDomainType())
		{
			int iDistToCOM = plotDistance(*pUnit->plot(),*pCOM);
			int iDistToTarget = plotDistance(pUnit->getX(),pUnit->getY(),GetGoalX(),GetGoalY());
			vPlots.push_back( SPlotWithScore(pUnit->plot(),iDistToCOM*100+iDistToTarget) );
		}

		pUnit = GetNextUnit();
	}

	if (vPlots.empty())
		return NULL;

	//this sorts ascending!
	std::sort(vPlots.begin(),vPlots.end());
	return vPlots.front().pPlot;
}
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired)
{
	CvPlot* pRtnValue = NULL;
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;
	UnitHandle pUnit;
	int iReferenceUnitX = -1;
	int iWorldWidth = GC.getMap().getGridWidth();

	pUnit = GetFirstUnit();
	if(pUnit)
	{
		iReferenceUnitX = pUnit->getX();
	}

	while(pUnit)
	{
		int iUnitX = pUnit->getX();

		bool bWorldWrapAdjust = false;
		int iDiff = iUnitX - iReferenceUnitX;
		if(abs(iDiff) > (iWorldWidth / 2))
		{
			bWorldWrapAdjust = true;
		}

		if(bWorldWrapAdjust)
		{
			iTotalX += iUnitX + iWorldWidth;
		}
		else
		{
			iTotalX += iUnitX;
		}
		iTotalY += pUnit->getY();
		iNumUnits++;
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits;
		if(iAverageX >= iWorldWidth)
		{
			iAverageX = iAverageX - iWorldWidth;
		}
		int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits;
		pRtnValue = GC.getMap().plot(iAverageX, iAverageY);
	}

	// Domain check
	if (eDomainRequired != NO_DOMAIN && pRtnValue)
	{
		if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA)
		{
			// Find an adjacent plot that works
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI));
				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
					{
						return pLoopPlot;
					}
				}
			}

			// Try two plots out if really having problems
			for (int iDX = -2; iDX <= 2; iDX++)
			{
				for (int iDY = -2; iDY <= 2; iDY++)
				{
					CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2);
					if (pLoopPlot)
					{
						if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2)
						{
							if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
							{
								return pLoopPlot;
							}
						}
					}
				}
			}

			// Give up - just use location of first unit
			pUnit = GetFirstUnit();
			pRtnValue = pUnit->plot();
		}
	}

	return pRtnValue;
}
Beispiel #11
0
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired)
{
	CvPlot* pRtnValue = NULL;
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;
	UnitHandle pUnit;
	int iReferenceUnitX = -1;
	int iWorldWidth = GC.getMap().getGridWidth();

	pUnit = GetFirstUnit();
	if(pUnit)
	{
		iReferenceUnitX = pUnit->getX();
	}

	while(pUnit)
	{
		int iUnitX = pUnit->getX();

		bool bWorldWrapAdjust = false;
		int iDiff = iUnitX - iReferenceUnitX;
		if(abs(iDiff) > (iWorldWidth / 2))
		{
			bWorldWrapAdjust = true;
		}

		if(bWorldWrapAdjust)
		{
			iTotalX += iUnitX + iWorldWidth;
		}
		else
		{
			iTotalX += iUnitX;
		}
		iTotalY += pUnit->getY();
		iNumUnits++;
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits;
		if(iAverageX >= iWorldWidth)
		{
			iAverageX = iAverageX - iWorldWidth;
		}
		int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits;
		pRtnValue = GC.getMap().plot(iAverageX, iAverageY);
	}

	// Domain check
	if (eDomainRequired != NO_DOMAIN && pRtnValue)
	{
		if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA)
		{
			// Find an adjacent plot that works
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI));
				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
					{
						return pLoopPlot;
					}
				}
			}

			// Try two plots out if really having problems
#ifdef AUI_HEXSPACE_DX_LOOPS
			int iMaxDX, iDX;
			CvPlot* pLoopPlot;
			for (int iDY = -2; iDY <= 2; iDY++)
			{
				iMaxDX = 2 - MAX(0, iDY);
				for (iDX = -2 - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!)
				{
					// No need for range check because loops are set up properly
					pLoopPlot = plotXY(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY);
					if (pLoopPlot)
					{
						if (hexDistance(iDX, iDY) == 2)
#else
			for (int iDX = -2; iDX <= 2; iDX++)
			{
				for (int iDY = -2; iDY <= 2; iDY++)
				{
					CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2);
					if (pLoopPlot)
					{
#ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE
						if (hexDistance(iDX, iDY) == 2)
#else
						if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2)
#endif
#endif
						{
							if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
							{
								return pLoopPlot;
							}
						}
					}
				}
			}

			// Give up - just use location of first unit
			pUnit = GetFirstUnit();
			pRtnValue = pUnit->plot();
		}
	}

	return pRtnValue;
}

/// Return distance from this plot of unit in army farthest away
int CvArmyAI::GetFurthestUnitDistance(CvPlot* pPlot)
{
	int iLargestDistance = 0;
	UnitHandle pUnit;
	int iNewDistance;

	pUnit = GetFirstUnit();
	while(pUnit)
	{
		iNewDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY());
		if(iNewDistance > iLargestDistance)
		{
			iLargestDistance = iNewDistance;
		}
		pUnit = GetNextUnit();
	}
	return iLargestDistance;
}

// FORMATION ACCESSORS

/// Retrieve index of the formation used by this army
int CvArmyAI::GetFormationIndex() const
{
	return m_iFormationIndex;
}

/// Set index of the formation used by this army
void CvArmyAI::SetFormationIndex(int iFormationIndex)
{
	CvArmyFormationSlot slot;

	if(m_iFormationIndex != iFormationIndex)
	{
		m_iFormationIndex = iFormationIndex;

		CvMultiUnitFormationInfo* thisFormation = GC.getMultiUnitFormationInfo(m_iFormationIndex);
		if(thisFormation)
		{
			int iNumSlots = thisFormation->getNumFormationSlotEntries();

			// Build all the formation entries
			m_FormationEntries.clear();
			for(int iI = 0; iI < iNumSlots; iI++)
			{
				slot.SetUnitID(ARMY_NO_UNIT);
				slot.SetTurnAtCheckpoint(ARMYSLOT_UNKNOWN_TURN_AT_CHECKPOINT);
				m_FormationEntries.push_back(slot);
			}
		}
	}
}

/// How many slots are there in this formation if filled
int CvArmyAI::GetNumFormationEntries() const
{
	return m_FormationEntries.size();
}

/// How many slots do we currently have filled?
int CvArmyAI::GetNumSlotsFilled() const
{
	int iRtnValue = 0;

	for(unsigned int iI = 0; iI < m_FormationEntries.size(); iI++)
	{
		if(m_FormationEntries[iI].m_iUnitID != ARMY_NO_UNIT)
		{
			iRtnValue++;
		}
	}
	return iRtnValue;
}
// Supplies units - must be called by Campaign Master
int SupplyUnits (Team who, CampaignTime deltaTime)
{
	Objective		o,s;
	Unit			unit;
	int				supply,fuel,replacements,gots,gotf,type;
	int				sneeded=0,fneeded=0,rneeded=0;
	float			sratio,fratio,rratio;
	GridIndex		x,y;
	MissionRequestClass	mis;
	// A.S. begin additional variables 2001-12-09
	// A.S. We now distinguish between aircrafts and ground vehicles 
	int				rneeded_a=0, rneeded_v=0, repl_a=0, repl_v=0;	
	float			rratio_a, rratio_v,	a_v_nratio, repl; 			// A.S. 
	float			sqnbonus, lambda;								// A.S. 
	int				repl_a_s = 0, repl_v_s = 0, repl_s = 0, repl_sa = 0, prob = 0;	// A.S. debug variables
	// end added section

	if (!TeamInfo[who] || !(TeamInfo[who]->flags & TEAM_ACTIVE))
		return 0;

	sratio = fratio = rratio = 0.0F;

	// A.S. begin, 2001-12-09.
	rratio_a = rratio_v = a_v_nratio = repl = lambda = 0.0F;		// A.S.
	sqnbonus = RelSquadBonus;									    // A.S. gives Sqn relative (!) more repl. than Bde.
	// end added section

	// zero supply values
	{
		VuListIterator objit(AllObjList);
		o = GetFirstObjective(&objit);
		while (o){
			if (o->GetTeam() == who)
				o->static_data.local_data = 0;
			o = GetNextObjective(&objit);
		}
	}

	// Calculate needs
	{
		VuListIterator myit(AllUnitList);
		unit = GetFirstUnit(&myit);
		while (unit)
		{
			if (unit->GetTeam() == who && (unit->IsBattalion() || unit->IsSquadron()))
			{
				sneeded += unit->GetUnitSupplyNeed(FALSE);
				fneeded += unit->GetUnitFuelNeed(FALSE);
				rneeded += unit->GetFullstrengthVehicles() - unit->GetTotalVehicles();
				// A.S. begin
				if (unit->IsSquadron() && NoTypeBonusRepl)		// A.S. extra calculation for squadrons 
				{
					rneeded_a += unit->GetFullstrengthVehicles() - unit->GetTotalVehicles(); 
				}														

				// end added section
			}
			unit = GetNextUnit(&myit);
		}
	}


	// A.S. begin, 2001-12-09.
	if (NoTypeBonusRepl) { 
		rneeded_v = rneeded - rneeded_a;						//A.S. calculation for groud vehicles
		if (rneeded > 0)
			a_v_nratio = ( (float)rneeded_a ) / rneeded;
		else
			a_v_nratio = 1;
		repl = (float)TeamInfo[who]->GetReplacementsAvail();    // aggregate replacements available
		lambda =  a_v_nratio * sqnbonus;
		if (lambda > 1)
			lambda = 1;
	}
	// end added section
	

	// Calculate the maximum ratio of supply we can give out
	if (sneeded > 0)
		sratio = (float)TeamInfo[who]->GetSupplyAvail() / sneeded;
	if (sratio > MAX_SUPPLY_RATIO)
		sratio = MAX_SUPPLY_RATIO;
	if (fneeded > 0)
		fratio = (float)TeamInfo[who]->GetFuelAvail() / fneeded;
	if (fratio > MAX_SUPPLY_RATIO)
		fratio = MAX_SUPPLY_RATIO;
	if (rneeded > 0)
		rratio = (float)TeamInfo[who]->GetReplacementsAvail() / rneeded;

	if (!NoTypeBonusRepl) // A.S. added if-condiion 2001-12-09 
	{
		if (rratio > 0.25F)	
			rratio = 0.25F;		
	}

	// A.S. begin, 2001-12-09
	if  (NoTypeBonusRepl) 
	{ 
		if (rratio > MAX_SUPPLY_RATIO) {		
			rratio = MAX_SUPPLY_RATIO;
		}
		if (rneeded_a > 0)
			rratio_a = repl / rneeded_a;			
		else
			rratio_a = MAX_SUPPLY_RATIO;
		if (rneeded_v > 0)
			rratio_v = repl / rneeded_v;
		else
			rratio_v = MAX_SUPPLY_RATIO;
		
		if (rratio_a > MAX_SUPPLY_RATIO)
			rratio_a = MAX_SUPPLY_RATIO;
		if (rratio_v > MAX_SUPPLY_RATIO)
			rratio_v = MAX_SUPPLY_RATIO;
		if (repl == 0) {							// to handle situations like 0/0 !
			rratio_a = 0;
			rratio_v = 0;
		}
	}
	// end added section


	// Supply units
	{
		VuListIterator myit(AllUnitList);
		unit = GetFirstUnit(&myit);
		while (unit)
		{
			// We only supply/repair Battalions and Squadrons
			if (
				unit->GetTeam() == who && (unit->IsBattalion() || unit->IsSquadron()) &&
				TheCampaign.CurrentTime - unit->GetLastResupplyTime() > unit->GetUnitSupplyTime()
			){
				float			typeBonus = 1.0F;

				if (unit->GetUnitCurrentRole() == GRO_ATTACK)
					typeBonus = 6.0F;
				if (unit->IsSquadron())
				{
					((SquadronClass*)unit)->ReinforcePilots(2);
					typeBonus = 2.0F;
				}
				// Add some randomness
				typeBonus += ((rand()%50)-25.0F)/100.0F;
				if (typeBonus < 0.0F)
					typeBonus = 0.0F;

				supply = FloatToInt32(unit->GetUnitSupplyNeed(FALSE) * sratio * typeBonus);
				fuel = FloatToInt32(unit->GetUnitFuelNeed(FALSE) * fratio * typeBonus);

				// A.S.  2001-12-09. No Type Bonus for replacements. This helps fixing the bug that units can get more replacements than available.
				if (NoTypeBonusRepl)
					typeBonus = 1.0F;		
				// end added section
				
				replacements = FloatToInt32((unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * rratio * typeBonus);

				// A.S. begin, 2001-12-09
				repl_s += replacements;				// debug
				if (NoTypeBonusRepl) 	// New code for distinguishing between aircrafts and ground vehicles 
				{
					if (unit->IsSquadron())				// this algorithm guarantees that no team can get more repl than available
					{
						prob = rand() % 100;
						repl_a = FloatToInt32((unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (lambda) * rratio_a);
						if ( TeamInfo[who]->GetReplacementsAvail() >= 1  && prob < 51  &&  ( ((float)unit->GetTotalVehicles())/unit->GetFullstrengthVehicles() <= 0.8F)) // rounding up with probability 0.5
							repl_a = FloatToInt32( (float) ceil( (unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (lambda) * rratio_a) );
						if (repl_a > 0) 
						{
							TeamInfo[who]->SetReplacementsAvail( TeamInfo[who]->GetReplacementsAvail() - repl_a );
							unit->ChangeVehicles( min(repl_a, TeamInfo[who]->GetReplacementsAvail()) );
							repl_a_s += min(repl_a, TeamInfo[who]->GetReplacementsAvail()); // debug
						}
					}	
					else {
						prob = rand() % 100;
						repl_v = FloatToInt32((unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (1 - lambda) * rratio_v);
						if ( TeamInfo[who]->GetReplacementsAvail() > 12  && prob < 51  &&  ( ((float)unit->GetTotalVehicles())/unit->GetFullstrengthVehicles() <= 0.85F)) // rounding up
							repl_v = FloatToInt32( (float) ceil( (unit->GetFullstrengthVehicles() - unit->GetTotalVehicles()) * (1 - lambda) * rratio_v) );
						if (repl_v > 0) 
						{
							TeamInfo[who]->SetReplacementsAvail(TeamInfo[who]->GetReplacementsAvail() - repl_v);
							unit->ChangeVehicles( min(repl_v, TeamInfo[who]->GetReplacementsAvail()) );
							repl_v_s += min(repl_v, TeamInfo[who]->GetReplacementsAvail()); // debug
						}
					}
					// prob = rand() % 100;
				}
				else 
				{							
					if (replacements)	// ++++++ old code begin ++++++
					{
					TeamInfo[who]->SetReplacementsAvail(TeamInfo[who]->GetReplacementsAvail() - replacements);
					if (unit->IsSquadron())
						{
						repl_sa += replacements; // A.S. debug
						TeamInfo[who]->SetReplacementsAvail(TeamInfo[who]->GetReplacementsAvail() - replacements);
						unit->SetLastResupply(replacements);
						}
					unit->ChangeVehicles(replacements);
					}
				}	// end added section  (important: this section replaces(!) the section marked with ++++++ old code ++++++ !)
				
				if (fuel || supply)
				{
					unit->GetLocation(&x,&y);
					o = FindNearestFriendlyObjective(who, &x, &y, 0);
					if (o)
					{
						s = FindNearestSupplySource(o);
						if (s)
						{
							TeamInfo[who]->SetSupplyAvail(TeamInfo[who]->GetSupplyAvail() - supply);
							TeamInfo[who]->SetFuelAvail(TeamInfo[who]->GetFuelAvail() - fuel);
							gots = supply;
							gotf = fuel;
							if (SendSupply(s,o,&gots,&gotf))
								SupplyUnit(unit,supply,gots,fuel,gotf);
						}
					}
				}
				unit->SetLastResupplyTime(TheCampaign.CurrentTime);
			}
			unit = GetNextUnit(&myit);
		}
	}

	// A.S. debug begin
	//if (NoTypeBonusRepl) {
	//	if (who == 2 || who==6) {	
	//		FILE *deb;
	//		deb = fopen("c:\\temp\\deb1.txt", "a");
	//		fprintf(deb, "Team %2d  ReplaAvail = %3d  A_Needed = %3d  V_Needed %4d  Aircraft = %2d  Vehicle = %3d  TIME = %d\n", who, (int)repl, rneeded_a, rneeded_v, repl_a_s, repl_v_s, TheCampaign.CurrentTime );   
	//		fclose(deb);
	//	}
	//}
	//else {
	//	if (who == 2 || who==6) {	// A.S. debug
	//		FILE *deb;
	//		deb = fopen("c:\\temp\\deb1.txt", "a");
	//		fprintf(deb, "Team %2d  ReplaAvail = %3d  Needed = %3d | Repl_a = %2d repl_v = %3d | TIME = %d\n", who, TeamInfo[who]->GetReplacementsAvail(), rneeded, repl_sa, (repl_s-repl_sa) , TheCampaign.CurrentTime % CampaignHours );   
	//		fclose(deb);
	//	}
	//}
	// A.S. debug end

	// Reset loss values, set supply values, and request missions
	{
		VuListIterator objit(AllObjList);
		o = GetFirstObjective(&objit);
		while (o){
			if (o->GetTeam() == who){
				supply = LOBYTE(o->static_data.local_data);
				fuel = HIBYTE(o->static_data.local_data);
				if (supply > 5 || fuel > 5){
					o->SendObjMessage(o->Id(),FalconObjectiveMessage::objSetSupply,(short)(supply),(short)(fuel),0);
					type = o->GetType();
					if (type == TYPE_ROAD || type == TYPE_INTERSECT)
					{
						// Request an interdiction mission
						mis.requesterID = o->Id();
						o->GetLocation(&mis.tx,&mis.ty);
						mis.vs = o->GetTeam();
						mis.who = GetEnemyTeam(mis.vs);
						mis.tot = Camp_GetCurrentTime() + (30+rand()%480)*CampaignMinutes;
						mis.tot_type = TYPE_NE;
						mis.targetID = FalconNullId;
						mis.mission = AMIS_INT;
						mis.roe_check = ROE_AIR_ATTACK;
						mis.context = enemySupplyInterdictionZone;
						mis.RequestMission();
					}
					// RV - Biker - Do something special for bridges
					//if (type == TYPE_BRIDGE || type == TYPE_DEPOT || type == TYPE_PORT)
					if (type == TYPE_DEPOT || type == TYPE_PORT)
					{
						// Request an interdiction strike mission
						mis.requesterID = o->Id();
						o->GetLocation(&mis.tx,&mis.ty);
						mis.vs = o->GetTeam();
						mis.who = GetEnemyTeam(mis.vs);
						mis.tot = Camp_GetCurrentTime() + (30+rand()%480)*CampaignMinutes;
						mis.tot_type = TYPE_NE;
						mis.targetID = o->Id();
						mis.mission = AMIS_INTSTRIKE;
						mis.roe_check = ROE_AIR_ATTACK;

						if (type == TYPE_DEPOT)
								mis.context = enemySupplyInterdictionDepot;
						if (type == TYPE_PORT)
								mis.context = enemySupplyInterdictionPort;
						mis.RequestMission();
					}
					if (type == TYPE_BRIDGE) {
						// Check distance to FLOT
						GridIndex ox = 0, oy = 0;
						o->GetLocation(&ox, &oy);
						float dist = DistanceToFront(ox,oy);

						if (dist >= 50.0f) {
							mis.requesterID = o->Id();
							mis.tx = ox;
							mis.ty = oy;
							mis.vs = o->GetTeam();
							mis.who = GetEnemyTeam(mis.vs);
							mis.tot = Camp_GetCurrentTime() + (30+rand()%480)*CampaignMinutes;
							mis.tot_type = TYPE_NE;
							mis.targetID = o->Id();
							mis.mission = AMIS_INTSTRIKE;
							mis.roe_check = ROE_AIR_ATTACK;
							mis.context = enemySupplyInterdictionBridge;
							mis.RequestMission();
						}
					}
				}
			}
			o = GetNextObjective(&objit);
		}
	}
	return 1;
}
/// Get center of mass of units in army (account for world wrap!)
CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired)
{
	int iTotalX = 0;
	int iTotalY = 0;
	int iNumUnits = 0;

#if defined(MOD_BALANCE_CORE)
	UnitHandle pUnit = GetFirstUnit();

	if (!pUnit)
		return NULL;

	int iTotalX2 = 0;
	int iTotalY2 = 0;
	int iWorldWidth = GC.getMap().getGridWidth();
	int iWorldHeight = GC.getMap().getGridHeight();

	//the first unit is our reference ...
	int iRefX = pUnit->getX();
	int iRefY = pUnit->getY();
	iNumUnits++;
	pUnit = GetNextUnit();

	while(pUnit)
	{
		int iDX = pUnit->getX() - iRefX;
		int iDY = pUnit->getY() - iRefY;

		if (GC.getMap().isWrapX())
		{
			if( iDX > +(iWorldWidth / 2))
				iDX -= iWorldWidth;
			if( iDX < -(iWorldWidth / 2))
				iDX += iWorldWidth;
		}
		if (GC.getMap().isWrapY())
		{
			if( iDY > +(iWorldHeight / 2))
				iDY -= iWorldHeight;
			if( iDY < -(iWorldHeight / 2))
				iDY += iWorldHeight;
		}

		iTotalX += iDX;
		iTotalY += iDY;
		iTotalX2 += iDX*iDX;
		iTotalY2 += iDY*iDY;
		iNumUnits++;

		pUnit = GetNextUnit();
	}

	if (iNumUnits==0)
		return NULL;

	//this is for debugging
	float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits);
	float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits);

	//finally, compute average (with rounding)
	int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX;
	int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY;

	if (fVarX > 64 || fVarY > 64)
	{
		CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY);
		OutputDebugString( msg.c_str() );
	}

	//this handles wrapped coordinates
	CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY);

	if (!pCOM)
		return NULL;

	//don't return it directly but use the plot of the closest unit
	pUnit = GetFirstUnit();
	std::vector<SPlotWithScore> vPlots;
	while (pUnit)
	{
		if (eDomainRequired == NO_DOMAIN || pUnit->plot()->getDomain()==eDomainRequired)
			vPlots.push_back( SPlotWithScore(pUnit->plot(),plotDistance(*pUnit->plot(),*pCOM)) );

		pUnit = GetNextUnit();
	}

	if (vPlots.empty())
		return NULL;

	//this sorts ascending!
	std::sort(vPlots.begin(),vPlots.end());
	return vPlots.front().pPlot;

#else
	CvPlot* pRtnValue = NULL;
	UnitHandle pUnit;
	int iReferenceUnitX = -1;
	int iWorldWidth = GC.getMap().getGridWidth();

	pUnit = GetFirstUnit();
	if(pUnit)
	{
		iReferenceUnitX = pUnit->getX();
	}

	while(pUnit)
	{
		int iUnitX = pUnit->getX();

		bool bWorldWrapAdjust = false;
		int iDiff = iUnitX - iReferenceUnitX;
		if(abs(iDiff) > (iWorldWidth / 2))
		{
			bWorldWrapAdjust = true;
		}

		if(bWorldWrapAdjust)
		{
			iTotalX += iUnitX + iWorldWidth;
		}
		else
		{
			iTotalX += iUnitX;
		}
		iTotalY += pUnit->getY();
		iNumUnits++;
		pUnit = GetNextUnit();
	}

	if(iNumUnits > 0)
	{
		int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits;
		if(iAverageX >= iWorldWidth)
		{
			iAverageX = iAverageX - iWorldWidth;
		}
		int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits;
		pRtnValue = GC.getMap().plot(iAverageX, iAverageY);
	}

	// Domain check
	if (eDomainRequired != NO_DOMAIN && pRtnValue)
	{
		if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA)
		{
			// Find an adjacent plot that works
			for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI));
				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
					{
						return pLoopPlot;
					}
				}
			}

			// Try two plots out if really having problems
			for (int iDX = -2; iDX <= 2; iDX++)
			{
				for (int iDY = -2; iDY <= 2; iDY++)
				{
					CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2);
					if (pLoopPlot)
					{
						if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2)
						{
							if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND)
							{
								return pLoopPlot;
							}
						}
					}
				}
			}

			// Give up - just use location of first unit
			pUnit = GetFirstUnit();
			pRtnValue = pUnit->plot();
		}
	}
	return pRtnValue;
#endif
}