Bazaar developer reference

CvTacticalAI::ExecuteFlankAttack(CvTacticalTarget &)

Defined in
CvTacticalAI.cpp, line 8154
Class
CvTacticalAI
Hook name
CivHooks::CvTacticalAI_ExecuteFlankAttack

Hooks

static bool BeforeCvTacticalAI_ExecuteFlankAttack(CvTacticalAI* self, CvTacticalTarget& kTarget, bool& result);static void AfterCvTacticalAI_ExecuteFlankAttack(CvTacticalAI* self, CvTacticalTarget& kTarget, bool& result);static bool ReplaceCvTacticalAI_ExecuteFlankAttack(bool (*original)(CvTacticalAI*, CvTacticalTarget&), CvTacticalAI* self, CvTacticalTarget& kTarget);CivRegisterBefore<CivHooks::CvTacticalAI_ExecuteFlankAttack>(host, &BeforeCvTacticalAI_ExecuteFlankAttack);CivRegisterAfter<CivHooks::CvTacticalAI_ExecuteFlankAttack>(host, &AfterCvTacticalAI_ExecuteFlankAttack);CivRegisterReplace<CivHooks::CvTacticalAI_ExecuteFlankAttack>(host, &ReplaceCvTacticalAI_ExecuteFlankAttack);

Code

8153/// Take a multi-hex attack on an enemy unit this turn8154bool CvTacticalAI::ExecuteFlankAttack(CvTacticalTarget& kTarget)8155{8156#if defined(MOD_AI_SMART_V3)8157	if (MOD_AI_SMART_V3)8158	{8159	CvPlot* pLoopPlot;8160	int iPlotIndex;8161	vector<int> movedUnits;8162	CvTacticalAnalysisCell* pCell;8163	vector<CvTacticalTarget*> flankPlots;8164	m_TempTargets.clear();81658166	//Check all target plots.8167	for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)8168	{8169		pLoopPlot = plotDirection(kTarget.GetTargetX(), kTarget.GetTargetY(), ((DirectionTypes)iI));8170		if (pLoopPlot)8171		{8172			iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());8173			pCell = m_pMap->GetCell(iPlotIndex);8174			if(pCell->IsHelpsProvidesFlankBonus())8175			{8176				FindClosestUnit(pLoopPlot, 1, true/*bMustHaveHalfHP*/, false /*bMustBeRangedUnit*/, 0 /*iRangeRequired*/, false /*bNeedsIgnoreLOS*/, true /*bMustBeMeleeUnit*/);8177				if (!m_CurrentMoveUnits.empty())8178				{8179					// Store the plot and a score, less units found, higher the score8180					CvTacticalTarget target;8181					target.SetTargetX(pLoopPlot->getX());8182					target.SetTargetY(pLoopPlot->getY());8183					target.SetAuxIntData(1000 - m_CurrentMoveUnits.size());8184					m_TempTargets.push_back(target);8185					CvString strMsg0;8186					strMsg0.Format("Found %d units to flank at X: %d, Y: %d",  m_CurrentMoveUnits.size(), pLoopPlot->getX(), pLoopPlot->getY());8187					LogTacticalMessage(strMsg0, false);81888189				}8190			}8191		}8192	}81938194	if (!m_TempTargets.empty())8195	{8196		// Sort by the score to maximice efficiency moving units to flank targets8197		std::stable_sort(m_TempTargets.begin(), m_TempTargets.end());8198		for(unsigned int iI = 0; iI < m_TempTargets.size(); iI++)8199		{8200			UnitHandle pUnit;8201			CvPlot* targetPlot = GC.getMap().plot(m_TempTargets[iI].GetTargetX(), m_TempTargets[iI].GetTargetY());8202			FindClosestUnit(targetPlot, 1, true/*bMustHaveHalfHP*/, false /*bMustBeRangedUnit*/, 0 /*iRangeRequired*/, false /*bNeedsIgnoreLOS*/, true /*bMustBeMeleeUnit*/);8203			// We need to check if the unit has already moved into a flanking position.8204			for(unsigned int it = 0; it < m_CurrentMoveUnits.size(); it++)8205			{8206				bool validUnit = false;8207				std::vector<int>::iterator intIt;8208				for (intIt = movedUnits.begin(); intIt != movedUnits.end(); intIt++)8209				{8210					if (*intIt != m_CurrentMoveUnits[it].GetID())8211					{8212						validUnit = true;8213						break;8214					}8215				}8216				if (validUnit)8217				{8218					pUnit = m_pPlayer->getUnit(m_CurrentMoveUnits[it].GetID());8219					movedUnits.push_back(m_CurrentMoveUnits[it].GetID());8220					break;8221				}8222			}8223			if (pUnit)8224			{8225				pUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), targetPlot->getX(), targetPlot->getY());8226				if(GC.getLogging() && GC.getAILogging())8227				{8228					CvString strMsg;8229					strMsg.Format("Moving into a flanking position with %s, X: %d, Y: %d", pUnit->getName().GetCString(),8230									targetPlot->getX(), targetPlot->getY());8231					LogTacticalMessage(strMsg, false);8232				}82338234				if(!pUnit->canMove())8235				{8236					UnitProcessed(pUnit->GetID());8237				}			8238			}8239		}8240	}82418242	// Make the attacks anyways8243	CvPlot* pTargetPlot = GC.getMap().plot(kTarget.GetTargetX(), kTarget.GetTargetY());8244	UnitHandle pDefender = pTargetPlot->getVisibleEnemyDefender(m_pPlayer->GetID());8245	if(pDefender)8246	{8247		kTarget.SetAuxIntData(pDefender->GetCurrHitPoints());8248		m_CurrentMoveCities.clear();8249		if(FindUnitsWithinStrikingDistance(pTargetPlot, 1, 0, false /* bNoRangedUnits */))8250		{8251			ComputeTotalExpectedDamage(&kTarget, pTargetPlot);8252			ExecuteAttack(&kTarget, pTargetPlot, false/*bInflictWhatWeTake*/, true/*bMustSurviveAttack*/);8253		}8254	}82558256	}8257	else8258	{8259#endif8260	CvTacticalAnalysisCell* pCell;8261	CvPlot* pLoopPlot;8262	int iPlotIndex;8263	int iPossibleFlankHexes = 0;8264	CvTacticalTarget target;82658266	// Count number of possible flank attack spaces around target8267	for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)8268	{8269		pLoopPlot = plotDirection(kTarget.GetTargetX(), kTarget.GetTargetY(), ((DirectionTypes)iI));8270		if(pLoopPlot != NULL)8271		{8272			iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());8273			pCell = m_pMap->GetCell(iPlotIndex);8274			if(pCell->IsHelpsProvidesFlankBonus())8275			{8276				iPossibleFlankHexes++;8277			}8278		}8279	}82808281	// If more than 1, find how many we can fill with units8282	if(iPossibleFlankHexes > 1)8283	{8284		int iFillableHexes = 0;8285		int iNumAttackers = 0;8286		m_TempTargets.clear();8287		for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)8288		{8289			pLoopPlot = plotDirection(kTarget.GetTargetX(), kTarget.GetTargetY(), ((DirectionTypes)iI));8290			if(pLoopPlot != NULL)8291			{8292				iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());8293				pCell = m_pMap->GetCell(iPlotIndex);8294				if(pCell->IsHelpsProvidesFlankBonus())8295				{8296					if(FindClosestUnit(pLoopPlot, 0, true/*bMustHaveHalfHP*/, false /*bMustBeRangedUnit*/, 0 /*iRangeRequired*/, false /*bNeedsIgnoreLOS*/, true /*bMustBeMeleeUnit*/))8297					{8298						iFillableHexes++;8299						iNumAttackers++;8300						target.SetTargetX(pLoopPlot->getX());8301						target.SetTargetY(pLoopPlot->getY());8302						m_TempTargets.push_back(target);8303					}8304					// What about next turn?8305					else if(FindClosestUnit(pLoopPlot, 1, false/*bMustHaveHalfHP*/, false /*bMustBeRangedUnit*/, 0 /*iRangeRequired*/, false /*bNeedsIgnoreLOS*/, true /*bMustBeMeleeUnit*/))8306					{8307						iFillableHexes++;8308						target.SetTargetX(pLoopPlot->getX());8309						target.SetTargetY(pLoopPlot->getY());8310						m_TempTargets.push_back(target);8311					}8312				}8313			}8314		}83158316		// As long as we either get three hexes filled with one attacker, or two we can attack from, then this multi-hex attack is worth considering8317		if((iNumAttackers >= 1 && iFillableHexes >= 3) || iNumAttackers >= 2)8318		{8319			// Compute best way to fill the hexes8320			m_PotentialBlocks.clear();8321			for(unsigned int iI = 0; iI < m_TempTargets.size(); iI++)8322			{8323				pLoopPlot = GC.getMap().plot(m_TempTargets[iI].GetTargetX(), m_TempTargets[iI].GetTargetY());8324				if(!FindClosestUnit(pLoopPlot, 1, false/*bMustHaveHalfHP*/, false /*bMustBeRangedUnit*/, 0 /*iRangeRequired*/, false /*bNeedsIgnoreLOS*/, true /*bMustBeMeleeUnit*/))8325				{8326					iFillableHexes--;8327					if(iFillableHexes < 2)8328					{8329						return false;8330					}8331				}8332				else8333				{8334					// Save off the units that could get here8335					for(unsigned int jJ = 0; jJ < m_CurrentMoveUnits.size(); jJ++)8336					{8337						CvBlockingUnit block;8338						block.SetUnitID(m_CurrentMoveUnits[jJ].GetID());8339						block.SetPlot(pLoopPlot);8340						block.SetNumChoices((int)m_CurrentMoveUnits.size());8341						block.SetDistanceToTarget(m_CurrentMoveUnits[jJ].GetMovesToTarget());8342						m_PotentialBlocks.push_back(block);8343					}8344				}8345			}83468347			if(AssignFlankingUnits(iFillableHexes))8348			{8349				// Make moves up into hexes8350				for(unsigned int iI = 0; iI < m_ChosenBlocks.size(); iI++)8351				{8352					CvUnit* pUnit = m_pPlayer->getUnit(m_ChosenBlocks[iI].GetUnitID());8353					if(pUnit)8354					{8355						if(pUnit->plot() == m_ChosenBlocks[iI].GetPlot())8356						{8357							if(GC.getLogging() && GC.getAILogging())8358							{8359								CvString strMsg;8360								strMsg.Format("Already in a flanking position with %s, X: %d, Y: %d", pUnit->getName().GetCString(),8361								              m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8362								LogTacticalMessage(strMsg, false);8363							}8364						}8365						else8366						{8367							pUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8368							if(GC.getLogging() && GC.getAILogging())8369							{8370								CvString strMsg;8371								strMsg.Format("Moving into a flanking position with %s, X: %d, Y: %d", pUnit->getName().GetCString(),8372								              m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8373								LogTacticalMessage(strMsg, false);8374							}83758376							if(pUnit->getMoves() <= 0)8377							{8378								UnitProcessed(pUnit->GetID());8379							}8380						}8381					}8382				}83838384				// Make attacks8385				CvPlot* pTargetPlot = GC.getMap().plot(kTarget.GetTargetX(), kTarget.GetTargetY());8386				UnitHandle pDefender = pTargetPlot->getVisibleEnemyDefender(m_pPlayer->GetID());8387				if(pDefender)8388				{8389					kTarget.SetAuxIntData(pDefender->GetCurrHitPoints());8390					m_CurrentMoveCities.clear();8391					if(FindUnitsWithinStrikingDistance(pTargetPlot, 1, 0, false /* bNoRangedUnits */))8392					{8393						ComputeTotalExpectedDamage(&kTarget, pTargetPlot);8394						ExecuteAttack(&kTarget, pTargetPlot, false/*bInflictWhatWeTake*/, true/*bMustSurviveAttack*/);8395					}8396				}8397			}8398		}8399	}8400#if defined(MOD_AI_SMART_V3)8401	}8402#endif84038404	return false;8405}

Calls

Called by