Hooks
static bool BeforeCvTacticalAI_PlotDestroyUnitMoves(CvTacticalAI* self, AITacticalTargetType targetType, bool bMustBeAbleToKill, bool bAttackAtPoorOdds);static void AfterCvTacticalAI_PlotDestroyUnitMoves(CvTacticalAI* self, AITacticalTargetType targetType, bool bMustBeAbleToKill, bool bAttackAtPoorOdds);static void ReplaceCvTacticalAI_PlotDestroyUnitMoves(void (*original)(CvTacticalAI*, AITacticalTargetType, bool, bool), CvTacticalAI* self, AITacticalTargetType targetType, bool bMustBeAbleToKill, bool bAttackAtPoorOdds);CivRegisterBefore<CivHooks::CvTacticalAI_PlotDestroyUnitMoves>(host, &BeforeCvTacticalAI_PlotDestroyUnitMoves);CivRegisterAfter<CivHooks::CvTacticalAI_PlotDestroyUnitMoves>(host, &AfterCvTacticalAI_PlotDestroyUnitMoves);CivRegisterReplace<CivHooks::CvTacticalAI_PlotDestroyUnitMoves>(host, &ReplaceCvTacticalAI_PlotDestroyUnitMoves);
Code
2298/// Assign a group of units to attack each unit we think we can destroy2299void CvTacticalAI::PlotDestroyUnitMoves(AITacticalTargetType targetType, bool bMustBeAbleToKill, bool bAttackAtPoorOdds)2300{2301 int iRequiredDamage;2302 int iExpectedDamage;23032304 // See how many moves of this type we can execute2305 CvTacticalTarget* pTarget = GetFirstZoneTarget(targetType);2306 while(pTarget != NULL)2307 {2308 bool bUnitCanAttack = false;2309 bool bCityCanAttack = false;23102311 // See what units we have who can reach targets this turn2312 CvPlot* pPlot = GC.getMap().plot(pTarget->GetTargetX(), pTarget->GetTargetY());2313 UnitHandle pDefender = pPlot->getVisibleEnemyDefender(m_pPlayer->GetID());2314 if(pDefender)2315 {2316 bUnitCanAttack = FindUnitsWithinStrikingDistance(pPlot, 1, 0, false /* bNoRangedUnits */);2317 bCityCanAttack = FindCitiesWithinStrikingDistance(pPlot);2318 if(bUnitCanAttack || bCityCanAttack)2319 {2320 iExpectedDamage = ComputeTotalExpectedDamage(pTarget, pPlot);2321 iExpectedDamage += ComputeTotalExpectedBombardDamage(pDefender);2322 iRequiredDamage = pDefender->GetCurrHitPoints();2323 pTarget->SetAuxIntData(iRequiredDamage);23242325 if(!bMustBeAbleToKill)2326 {2327 // Put in any attacks where we'll inflict at least equal damage2328 if(GC.getLogging() && GC.getAILogging())2329 {2330 CvString strLogString;23312332 CvString strPlayerName = GET_PLAYER(pDefender->getOwner()).getCivilizationShortDescription();23332334 CvUnitEntry* pkUnitInfo = GC.getUnitInfo(pDefender->getUnitType());2335 CvString strTemp = (pkUnitInfo != NULL)? pkUnitInfo->GetDescription() : "Unknown Unit Type";23362337 switch(targetType)2338 {2339 case AI_TACTICAL_TARGET_HIGH_PRIORITY_UNIT:2340 strLogString.Format("Looking at damaging high priority %s, X: %d, Y: %d,", strTemp.GetCString(),2341 pDefender->getX(), pDefender->getY());2342 break;2343 case AI_TACTICAL_TARGET_MEDIUM_PRIORITY_UNIT:2344 strLogString.Format("Looking at damaging medium priority %s, X: %d, Y: %d,", strTemp.GetCString(),2345 pDefender->getX(), pDefender->getY());2346 break;2347 case AI_TACTICAL_TARGET_LOW_PRIORITY_UNIT:2348 strLogString.Format("Looking at damaging low priority %s, X: %d, Y: %d,", strTemp.GetCString(),2349 pDefender->getX(), pDefender->getY());2350 break;2351 }2352 strLogString += strPlayerName;2353 LogTacticalMessage(strLogString);2354 }23552356 // Attack no matter what2357 if(bAttackAtPoorOdds)2358 {2359 ExecuteAttack(pTarget, pPlot, false, false);2360 }2361 // If we can at least knock the defender to 40% strength with our combined efforts, go ahead even if each individual attack isn't favorable2362 else2363 {2364 bool bMustInflictWhatWeTake = true;2365 if (iExpectedDamage >= (iRequiredDamage * 40) / 100)2366 {2367 bMustInflictWhatWeTake = false;2368 }2369 ExecuteAttack(pTarget, pPlot, bMustInflictWhatWeTake, true);2370 }2371 }23722373 // Do we have enough firepower to destroy it?2374 else2375 {2376 if(iExpectedDamage > iRequiredDamage)2377 {2378 // If so, execute enough moves to destroy it2379 if(GC.getLogging() && GC.getAILogging())2380 {2381 CvString strLogString, strTemp, strPlayerName;2382 strPlayerName = GET_PLAYER(pDefender->getOwner()).getCivilizationShortDescription();2383 strTemp = GC.getUnitInfo(pDefender->getUnitType())->GetDescription();2384 switch(targetType)2385 {2386 case AI_TACTICAL_TARGET_HIGH_PRIORITY_UNIT:2387 strLogString.Format("Looking at killing high priority %s, X: %d, Y: %d,", strTemp.GetCString(),2388 pDefender->getX(), pDefender->getY());2389 break;2390 case AI_TACTICAL_TARGET_MEDIUM_PRIORITY_UNIT:2391 strLogString.Format("Looking at killing medium priority %s, X: %d, Y: %d,", strTemp.GetCString(),2392 pDefender->getX(), pDefender->getY());2393 break;2394 case AI_TACTICAL_TARGET_LOW_PRIORITY_UNIT:2395 strLogString.Format("Looking at killing low priority %s, X: %d, Y: %d,", strTemp.GetCString(),2396 pDefender->getX(), pDefender->getY());2397 break;2398 }2399 strLogString += strPlayerName;2400 LogTacticalMessage(strLogString);2401 }2402 ExecuteAttack(pTarget, pPlot, false, (targetType != AI_TACTICAL_TARGET_HIGH_PRIORITY_UNIT));2403 }2404 }2405 }2406 }2407 pTarget = GetNextZoneTarget();2408 }2409}