Hooks
static bool BeforeCvTacticalAI_ExecuteFormationMoves(CvTacticalAI* self, CvArmyAI* pArmy, CvPlot * pClosestCurrentCOMonPath);static void AfterCvTacticalAI_ExecuteFormationMoves(CvTacticalAI* self, CvArmyAI* pArmy, CvPlot * pClosestCurrentCOMonPath);static void ReplaceCvTacticalAI_ExecuteFormationMoves(void (*original)(CvTacticalAI*, CvArmyAI*, CvPlot *), CvTacticalAI* self, CvArmyAI* pArmy, CvPlot * pClosestCurrentCOMonPath);CivRegisterBefore<CivHooks::CvTacticalAI_ExecuteFormationMoves>(host, &BeforeCvTacticalAI_ExecuteFormationMoves);CivRegisterAfter<CivHooks::CvTacticalAI_ExecuteFormationMoves>(host, &AfterCvTacticalAI_ExecuteFormationMoves);CivRegisterReplace<CivHooks::CvTacticalAI_ExecuteFormationMoves>(host, &ReplaceCvTacticalAI_ExecuteFormationMoves);
Code
5187/// Complete moves for all units requested through calls to MoveWithFormation()5188void CvTacticalAI::ExecuteFormationMoves(CvArmyAI* pArmy, CvPlot *pClosestCurrentCOMonPath)5189{5190 CvPlot* pTarget;5191 UnitHandle pUnit;5192 AITacticalTargetType eTargetType;5193 CvPlot* pLoopPlot;5194 FStaticVector<CvOperationUnit, SAFE_ESTIMATE_NUM_MULTIUNITFORMATION_ENTRIES, true, c_eCiv5GameplayDLL, 0>::iterator it;51955196 if(m_OperationUnits.size() == 0)5197 {5198 return;5199 }52005201 pTarget = pArmy->Plot();52025203 int iMeleeUnits = 0;5204 int iRangedUnits = 0;5205 for(it = m_OperationUnits.begin(); it != m_OperationUnits.end(); it++)5206 {5207 CvUnit *pOpUnit = m_pPlayer->getUnit(it->GetUnitID());5208 if (pOpUnit->IsCanAttackRanged())5209 {5210 iRangedUnits++;5211 }5212 else5213 {5214 iMeleeUnits++;5215 }5216 }52175218 // See if we have enough places to put everyone5219 if(!ScoreFormationPlots(pArmy, pTarget, pClosestCurrentCOMonPath, iMeleeUnits + iRangedUnits))5220 {5221 if(GC.getLogging() && GC.getAILogging())5222 {5223 CvString strLogString;5224 strLogString.Format("Operation aborting. Army ID: %d. Not enough spaces to deploy along formation's path", pArmy->GetID());5225 LogTacticalMessage(strLogString);5226 }5227 m_pPlayer->getAIOperation(pArmy->GetOperationID())->SetToAbort(AI_ABORT_NO_ROOM_DEPLOY);5228 }52295230 // Compute the moves to get the best deployment5231 else5232 {5233 std::stable_sort(m_TempTargets.begin(), m_TempTargets.end());52345235 // First loop for melee units who should be out front5236 int iMeleeUnitsToPlace = iMeleeUnits;5237 bool bDone = false;5238 for(unsigned int iI = 0; iI < m_TempTargets.size() && !bDone; iI++)5239 {5240 eTargetType = m_TempTargets[iI].GetTargetType();52415242 pLoopPlot = GC.getMap().plot(m_TempTargets[iI].GetTargetX(), m_TempTargets[iI].GetTargetY());52435244 // Don't use if there's already someone here5245 if (!pLoopPlot->getBestDefender(NO_PLAYER))5246 {5247 if(FindClosestOperationUnit(pLoopPlot, false /*bSafeForRanged*/, false /*bMustBeRangedUnit*/))5248 {5249 UnitHandle pInnerUnit = m_pPlayer->getUnit(m_CurrentMoveUnits[0].GetID());5250 bool bMoveWasSafe;5251 MoveToUsingSafeEmbark(pInnerUnit, pLoopPlot, bMoveWasSafe);5252 pInnerUnit->finishMoves();5253 if(GC.getLogging() && GC.getAILogging())5254 {5255 CvString strMsg;5256 strMsg.Format("Deploying melee unit, %s, To X: %d, To Y: %d, At X: %d, At Y: %d", pInnerUnit->getName().GetCString(), pLoopPlot->getX(), pLoopPlot->getY(), pInnerUnit->getX(), pInnerUnit->getY());5257 LogTacticalMessage(strMsg);5258 }5259 iMeleeUnitsToPlace--;5260 }5261 }5262 if (iMeleeUnitsToPlace == 0)5263 {5264 bDone = true;5265 }5266 }52675268 // Log if someone in army didn't get a move assigned5269 if (iMeleeUnitsToPlace > 0)5270 {5271 if(GC.getLogging() && GC.getAILogging())5272 {5273 CvString strMsg;5274 strMsg.Format("No army deployment move for %d melee units", iMeleeUnitsToPlace);5275 LogTacticalMessage(strMsg);5276 }5277 }52785279 // Second loop for ranged units5280 int iRangedUnitsToPlace = iRangedUnits;5281 bDone = false;5282 for(unsigned int iI = 0; iI < m_TempTargets.size() && !bDone; iI++)5283 {5284 eTargetType = m_TempTargets[iI].GetTargetType();52855286 pLoopPlot = GC.getMap().plot(m_TempTargets[iI].GetTargetX(), m_TempTargets[iI].GetTargetY());5287 if (eTargetType == AI_TACTICAL_TARGET_HIGH_PRIORITY_UNIT)5288 {5289 // Don't use if there's already someone here5290 if (!pLoopPlot->getBestDefender(NO_PLAYER))5291 {5292 if(FindClosestOperationUnit(pLoopPlot, true /*bSafeForRanged*/, true /*bMustBeRangedUnit*/))5293 {5294 UnitHandle pInnerUnit = m_pPlayer->getUnit(m_CurrentMoveUnits[0].GetID());5295 bool bMoveWasSafe;5296 MoveToUsingSafeEmbark(pInnerUnit, pLoopPlot, bMoveWasSafe);5297 pInnerUnit->finishMoves();5298 if(GC.getLogging() && GC.getAILogging())5299 {5300 CvString strMsg;5301 strMsg.Format("Deploying ranged unit, %s, To X: %d, To Y: %d, At X: %d, At Y: %d", pInnerUnit->getName().GetCString(), pLoopPlot->getX(), pLoopPlot->getY(), pInnerUnit->getX(), pInnerUnit->getY());5302 LogTacticalMessage(strMsg);5303 }5304 iRangedUnitsToPlace--;5305 }5306 }5307 }5308 if (iRangedUnitsToPlace == 0)5309 {5310 bDone = true;5311 }5312 }53135314 // Third loop for ranged units we couldn't put in an ideal spot5315 for(unsigned int iI = 0; iI < m_TempTargets.size() && !bDone; iI++)5316 {5317 eTargetType = m_TempTargets[iI].GetTargetType();53185319 pLoopPlot = GC.getMap().plot(m_TempTargets[iI].GetTargetX(), m_TempTargets[iI].GetTargetY());53205321 // Don't use if there's already someone here5322 if (!pLoopPlot->getBestDefender(NO_PLAYER))5323 {5324 if(FindClosestOperationUnit(pLoopPlot, true /*bSafeForRanged*/, true /*bMustBeRangedUnit*/))5325 {5326 UnitHandle pInnerUnit = m_pPlayer->getUnit(m_CurrentMoveUnits[0].GetID());5327 bool bMoveWasSafe;5328 MoveToUsingSafeEmbark(pInnerUnit, pLoopPlot, bMoveWasSafe);5329 pInnerUnit->finishMoves();5330 if(GC.getLogging() && GC.getAILogging())5331 {5332 CvString strMsg;5333 strMsg.Format("Deploying ranged unit (Pass 2), %s, To X: %d, To Y: %d, At X: %d, At Y: %d", pInnerUnit->getName().GetCString(), pLoopPlot->getX(), pLoopPlot->getY(), pInnerUnit->getX(), pInnerUnit->getY());5334 LogTacticalMessage(strMsg);5335 }5336 iRangedUnitsToPlace--;5337 }5338 }5339 if (iRangedUnitsToPlace == 0)5340 {5341 bDone = true;5342 }5343 }53445345 // Log if someone in army didn't get a move assigned5346 if (iRangedUnitsToPlace > 0)5347 {5348 if(GC.getLogging() && GC.getAILogging())5349 {5350 CvString strMsg;5351 strMsg.Format("No army deployment move for %d ranged units", iRangedUnitsToPlace);5352 LogTacticalMessage(strMsg);5353 }5354 }5355 }5356}