Bazaar developer reference

CvTacticalAI::ExecuteSafeBombards(CvTacticalTarget &)

Defined in
CvTacticalAI.cpp, line 7669
Class
CvTacticalAI
Hook name
CivHooks::CvTacticalAI_ExecuteSafeBombards

Hooks

static bool BeforeCvTacticalAI_ExecuteSafeBombards(CvTacticalAI* self, CvTacticalTarget& kTarget, bool& result);static void AfterCvTacticalAI_ExecuteSafeBombards(CvTacticalAI* self, CvTacticalTarget& kTarget, bool& result);static bool ReplaceCvTacticalAI_ExecuteSafeBombards(bool (*original)(CvTacticalAI*, CvTacticalTarget&), CvTacticalAI* self, CvTacticalTarget& kTarget);CivRegisterBefore<CivHooks::CvTacticalAI_ExecuteSafeBombards>(host, &BeforeCvTacticalAI_ExecuteSafeBombards);CivRegisterAfter<CivHooks::CvTacticalAI_ExecuteSafeBombards>(host, &AfterCvTacticalAI_ExecuteSafeBombards);CivRegisterReplace<CivHooks::CvTacticalAI_ExecuteSafeBombards>(host, &ReplaceCvTacticalAI_ExecuteSafeBombards);

Code

7668/// Bombard enemy units from plots they can't reach (return true if some attack made)7669bool CvTacticalAI::ExecuteSafeBombards(CvTacticalTarget& kTarget)7670{7671	CvTacticalUnit unit;7672	void* pFirstAttacker = NULL;7673	UnitHandle pDefender;7674	int iRequiredDamage = 0;7675	bool bCityCanAttack = false;7676	bool bFirstAttackCity = false;76777678	CvPlot* pTargetPlot = GC.getMap().plot(kTarget.GetTargetX(), kTarget.GetTargetY());7679	if(PlotAlreadyTargeted(pTargetPlot) != -1)7680	{7681		return false;7682	}76837684	// Get required damage on unit target7685	pDefender = pTargetPlot->getVisibleEnemyDefender(m_pPlayer->GetID());7686#if defined(MOD_AI_SMART_V3)7687	if(pDefender && (!MOD_AI_SMART_V3 || !pTargetPlot->getPlotCity()))7688#else7689	if(pDefender)7690#endif7691	{7692		iRequiredDamage = pDefender->GetCurrHitPoints();76937694		// If this is a unit target we might also be able to hit it with a city7695		bCityCanAttack = FindCitiesWithinStrikingDistance(pTargetPlot);7696		if(bCityCanAttack)7697		{7698			ComputeTotalExpectedBombardDamage(pDefender);76997700			// Start by applying damage from city bombards7701			for(unsigned int iI = 0; iI < m_CurrentMoveCities.size() && iRequiredDamage > 0; iI++)7702			{7703				CvCity* pCity = m_pPlayer->getCity(m_CurrentMoveCities[iI].GetID());7704				if(pCity != NULL)7705				{7706					if(QueueAttack(pCity, &kTarget, true /*bRanged*/, true /*bCity*/))7707					{7708						pFirstAttacker = (void*)pCity;7709						bFirstAttackCity = true;7710					}77117712					// Subtract off expected damage7713					iRequiredDamage -= m_CurrentMoveCities[iI].GetExpectedTargetDamage();7714				}7715			}7716		}7717	}77187719	// Get required damage on city target7720	else7721	{7722		CvCity* pCity = pTargetPlot->getPlotCity();7723		if(pCity != NULL)7724		{7725			iRequiredDamage = pCity->GetMaxHitPoints() - pCity->getDamage();77267727			// Can't eliminate a city with ranged fire, so don't target one if that low on health7728			if(iRequiredDamage <= 1)7729			{7730				return false;7731			}7732		}7733	}77347735	// Need to keep hitting target?7736	if(iRequiredDamage <= 0)7737	{7738		return false;7739	}77407741	// For each of our ranged units, see if they are already in a plot that can bombard that can't be attacked.7742	// If so, bombs away!7743	m_CurrentMoveUnits.clear();7744	list<int>::iterator it;7745	for(it = m_CurrentTurnUnits.begin(); it != m_CurrentTurnUnits.end(); it++)7746	{7747		UnitHandle pUnit = m_pPlayer->getUnit(*it);7748		if(pUnit && pUnit->IsCanAttackRanged() && !pUnit->isOutOfAttacks())7749		{7750			int iPlotIndex = GC.getMap().plotNum(pUnit->getX(), pUnit->getY());7751			CvTacticalAnalysisCell* pCell = GC.getGame().GetTacticalAnalysisMap()->GetCell(iPlotIndex);7752			if(pCell->IsWithinRangeOfTarget() && !pCell->IsSubjectToAttack() && IsExpectedToDamageWithRangedAttack(pUnit, pTargetPlot))7753			{7754				if(pUnit->canSetUpForRangedAttack(NULL))7755				{7756					pUnit->setSetUpForRangedAttack(true);7757					if(GC.getLogging() && GC.getAILogging())7758					{7759						CvString strMsg;7760						strMsg.Format("Set up %s for ranged attack", pUnit->getName().GetCString());7761						LogTacticalMessage(strMsg, false);7762					}7763				}77647765				if(pUnit->canMove() && pUnit->canRangeStrikeAt(kTarget.GetTargetX(), kTarget.GetTargetY()))7766				{7767					if(GC.getLogging() && GC.getAILogging())7768					{7769						CvString strMsg;7770						strMsg.Format("Making a safe bombard (no move) with %s, Target X: %d, Target Y: %d, At X: %d, At Y: %d", pUnit->getName().GetCString(),7771						              kTarget.GetTargetX(), kTarget.GetTargetY(), pUnit->getX(), pUnit->getY());7772						LogTacticalMessage(strMsg, false);7773					}77747775					if(QueueAttack((void*)pUnit.pointer(), &kTarget, true /*bRanged*/, false /*bCity*/))7776					{7777						pFirstAttacker = (void*)pUnit.pointer();7778					}77797780					// Save off ID so can be cleared from list to process for turn7781					unit.SetID(pUnit->GetID());7782					m_CurrentMoveUnits.push_back(unit);7783				}7784			}7785		}7786	}77877788	// Clear out the units we just processed from the list for this turn7789	std::vector<CvTacticalUnit>::iterator currMoveIt;7790	for(currMoveIt = m_CurrentMoveUnits.begin(); currMoveIt != m_CurrentMoveUnits.end(); ++currMoveIt)7791	{7792		UnitProcessed(currMoveIt->GetID());7793	}77947795	// For each plot that we can bombard from that the enemy can't attack, try and move a ranged unit there.7796	// If so, make that move and mark that tile as blocked with our unit.  If unit has movement left, queue up an attack7797	int iDX, iDY;7798	CvPlot* pLoopPlot;7799	int iPlotIndex;7800	CvTacticalAnalysisCell* pCell;78017802	for(int iTurnsToReach = 0; iTurnsToReach <= 2; iTurnsToReach++)7803	{7804		int iRange = m_pMap->GetBestFriendlyRange();78057806		for(iDX = -(iRange); iDX <= iRange; iDX++)7807		{7808			for(iDY = -(iRange); iDY <= iRange; iDY++)7809			{7810				pLoopPlot = plotXY(kTarget.GetTargetX(), kTarget.GetTargetY(), iDX, iDY);7811				if(pLoopPlot != NULL)7812				{7813					int iDistance = plotDistance(pLoopPlot->getX(), pLoopPlot->getY(), kTarget.GetTargetX(), kTarget.GetTargetY());7814					if(iDistance > 0 && iDistance <= iRange)7815					{7816						iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());7817						pCell = m_pMap->GetCell(iPlotIndex);7818						if(pCell->IsRevealed() && pCell->CanUseForOperationGathering())7819						{7820							if(pCell->IsWithinRangeOfTarget() && !pCell->IsSubjectToAttack())7821							{7822								bool bHaveLOS = pLoopPlot->canSeePlot(pTargetPlot, m_pPlayer->getTeam(), iRange, NO_DIRECTION);7823								if(FindClosestUnit(pLoopPlot, iTurnsToReach, false/*bMustHaveHalfHP*/, true/*bMustBeRangedUnit*/, iDistance, !bHaveLOS, false/*bMustBeMeleeUnit*/, true/*bIgnoreUnits*/, pTargetPlot))7824								{7825									UnitHandle pUnit = m_pPlayer->getUnit(m_CurrentMoveUnits[0].GetID());7826									if(pUnit)7827									{7828										// Check for presence of unmovable friendly units7829										UnitHandle pBlockingUnit = pLoopPlot->getBestDefender(m_pPlayer->GetID());7830										if(!pBlockingUnit || ExecuteMoveOfBlockingUnit(pBlockingUnit))7831										{7832											pUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), pLoopPlot->getX(), pLoopPlot->getY());78337834											if(GC.getLogging() && GC.getAILogging())7835											{7836												CvString strMsg;7837												strMsg.Format("Moving closer for safe bombard with %s, Target X: %d, Y: %d, Bombard From X: %d, Y: %d, Now At X: %d, Y: %d", pUnit->getName().GetCString(),7838												              kTarget.GetTargetX(), kTarget.GetTargetY(), pLoopPlot->getX(), pLoopPlot->getY(), pUnit->getX(), pUnit->getY());7839												LogTacticalMessage(strMsg, false);7840											}78417842											UnitProcessed(m_CurrentMoveUnits[0].GetID());78437844											if(pUnit->canSetUpForRangedAttack(NULL))7845											{7846												pUnit->setSetUpForRangedAttack(true);7847												if(GC.getLogging() && GC.getAILogging())7848												{7849													CvString strMsg;7850													strMsg.Format("Set up %s for ranged attack", pUnit->getName().GetCString());7851													LogTacticalMessage(strMsg, false);7852												}7853											}78547855											if(pUnit->canMove() && !pUnit->isOutOfAttacks() && pUnit->canRangeStrikeAt(kTarget.GetTargetX(), kTarget.GetTargetY()))7856											{7857												if(GC.getLogging() && GC.getAILogging())7858												{7859													CvString strMsg;7860													strMsg.Format("Making a safe bombard (half move) with %s, Target X: %d, Target Y: %d, At X: %d, At Y: %d", pUnit->getName().GetCString(),7861													              kTarget.GetTargetX(), kTarget.GetTargetY(), pUnit->getX(), pUnit->getY());7862													LogTacticalMessage(strMsg, false);7863												}78647865												if(QueueAttack((void*)pUnit.pointer(), &kTarget, true /*bRanged*/, false /*bCityAttack*/))7866												{7867													pFirstAttacker = (void*)pUnit.pointer();7868												}7869											}7870										}7871									}7872								}7873							}7874						}7875					}7876				}7877			}7878		}7879	}78807881	// Launch the initial attack plotted7882	if(pFirstAttacker)7883	{7884		LaunchAttack(pFirstAttacker, &kTarget, true /*bFirst*/, true /*bFirstAttackRanged*/, bFirstAttackCity);7885		return true;7886	}7887	return false;7888}

Calls

Called by