/// Find average speed of units in army int CvArmyAI::GetMovementRate() { int iMovementAverage = 2; // A reasonable default int iNumUnits = 0; int iTotalMovementAllowance = 0; CvUnit* pUnit; pUnit = GetFirstUnit(); while(pUnit) { iNumUnits++; iTotalMovementAllowance += pUnit->baseMoves(); pUnit = GetNextUnit(pUnit); } if(iNumUnits > 0) { iMovementAverage = (iTotalMovementAllowance + (iNumUnits / 2)) / iNumUnits; } return iMovementAverage; }
/// Updates the danger plots values to reflect threats across the map void CvDangerPlots::UpdateDanger (bool bPretendWarWithAllCivs, bool bIgnoreVisibility) { // danger plots have not been initialized yet, so no need to update if (!m_bArrayAllocated) { return; } // wipe out values int iGridSize = GC.getMap().numPlots(); CvAssertMsg(iGridSize == m_DangerPlots.size(), "iGridSize does not match number of DangerPlots"); for (int i = 0; i < iGridSize; i++) { m_DangerPlots[i] = 0; } CvPlayer& thisPlayer = GET_PLAYER(m_ePlayer); TeamTypes thisTeam = thisPlayer.getTeam(); // for each opposing civ for (int iPlayer = 0; iPlayer < MAX_PLAYERS; iPlayer++) { PlayerTypes ePlayer = (PlayerTypes)iPlayer; CvPlayer& loopPlayer = GET_PLAYER(ePlayer); TeamTypes eTeam = loopPlayer.getTeam(); if (!loopPlayer.isAlive()) { continue; } if (eTeam == thisTeam) { continue; } if (ShouldIgnorePlayer(ePlayer) && !bPretendWarWithAllCivs) { continue; } //for each unit int iLoop; CvUnit* pLoopUnit = NULL; for (pLoopUnit = loopPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = loopPlayer.nextUnit(&iLoop)) { if (ShouldIgnoreUnit(pLoopUnit, bIgnoreVisibility)) { continue; } int iRange = pLoopUnit->baseMoves(); if (pLoopUnit->canRangeStrike()) { iRange += pLoopUnit->GetRange(); } CvPlot* pUnitPlot = pLoopUnit->plot(); AssignUnitDangerValue(pLoopUnit, pUnitPlot); CvPlot* pLoopPlot = NULL; for (int iDX = -(iRange); iDX <= iRange; iDX++) { for (int iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXYWithRangeCheck(pUnitPlot->getX(), pUnitPlot->getY(), iDX, iDY, iRange); if (!pLoopPlot || pLoopPlot == pUnitPlot) { continue; } if (!pLoopUnit->canMoveOrAttackInto(*pLoopPlot) && !pLoopUnit->canRangeStrikeAt(pLoopPlot->getX(),pLoopPlot->getY())) { continue; } AssignUnitDangerValue(pLoopUnit, pLoopPlot); } } } // for each city CvCity* pLoopCity; for (pLoopCity = loopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = loopPlayer.nextCity(&iLoop)) { if (ShouldIgnoreCity(pLoopCity, bIgnoreVisibility)) { continue; } int iRange = GC.getCITY_ATTACK_RANGE(); CvPlot* pCityPlot = pLoopCity->plot(); AssignCityDangerValue(pLoopCity, pCityPlot); CvPlot* pLoopPlot = NULL; for (int iDX = -(iRange); iDX <= iRange; iDX++) { for (int iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXYWithRangeCheck(pCityPlot->getX(), pCityPlot->getY(), iDX, iDY, iRange); if (!pLoopPlot) { continue; } AssignCityDangerValue(pLoopCity, pLoopPlot); } } } } // Citadels int iCitadelValue = GetDangerValueOfCitadel(); int iPlotLoop; CvPlot *pPlot, *pAdjacentPlot; for (iPlotLoop = 0; iPlotLoop < GC.getMap().numPlots(); iPlotLoop++) { pPlot = GC.getMap().plotByIndexUnchecked(iPlotLoop); if (pPlot->isRevealed(thisTeam)) { ImprovementTypes eImprovement = pPlot->getRevealedImprovementType(thisTeam); if (eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0) { if (!ShouldIgnoreCitadel(pPlot, bIgnoreVisibility)) { for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)iI)); if (pAdjacentPlot != NULL) { AddDanger(pAdjacentPlot->getX(), pAdjacentPlot->getY(), iCitadelValue); } } } } } } // testing city danger values CvCity* pLoopCity; int iLoopCity = 0; for (pLoopCity = thisPlayer.firstCity(&iLoopCity); pLoopCity != NULL; pLoopCity = thisPlayer.nextCity(&iLoopCity)) { int iThreatValue = GetCityDanger(pLoopCity); pLoopCity->SetThreatValue(iThreatValue); } m_bDirty = false; }
// Indicate the plots we might want to move to that the enemy can attack void CvTacticalAnalysisMap::MarkCellsNearEnemy() { int iDistance; // Look at every cell on the map for(int iI = 0; iI < GC.getMap().numPlots(); iI++) { bool bMarkedIt = false; // Set true once we've found one that enemy can move past (worst case) CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(iI); if(m_pPlots[iI].IsRevealed() && !m_pPlots[iI].IsImpassableTerrain() && !m_pPlots[iI].IsImpassableTerritory()) { // Friendly cities always safe if(!m_pPlots[iI].IsFriendlyCity()) { if(!pPlot->isVisibleToEnemyTeam(m_pPlayer->getTeam())) { m_pPlots[iI].SetNotVisibleToEnemy(true); } else { for(unsigned int iUnitIndex = 0; iUnitIndex < m_EnemyUnits.size() && !bMarkedIt; iUnitIndex++) { CvUnit* pUnit = m_EnemyUnits[iUnitIndex]; if(pUnit->getArea() == pPlot->getArea()) { // Distance check before hitting pathfinder iDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY()); if(iDistance == 0) { m_pPlots[iI].SetSubjectToAttack(true); m_pPlots[iI].SetEnemyCanMovePast(true); bMarkedIt = true; } // TEMPORARY OPTIMIZATION: Assumes can't use roads or RR else if(iDistance <= pUnit->baseMoves()) { int iTurnsToReach; iTurnsToReach = TurnsToReachTarget(pUnit, pPlot, true /*bReusePaths*/, true /*bIgnoreUnits*/); // Its ok to reuse paths because when ignoring units, we don't use the tactical analysis map (which we are building) if(iTurnsToReach <= 1) { m_pPlots[iI].SetSubjectToAttack(true); } if(iTurnsToReach == 0) { m_pPlots[iI].SetEnemyCanMovePast(true); bMarkedIt = true; } } } } // Check adjacent plots for enemy citadels if(!m_pPlots[iI].IsSubjectToAttack()) { CvPlot* pAdjacentPlot; for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++) { pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)jJ)); if(pAdjacentPlot != NULL && pAdjacentPlot->getOwner() != NO_PLAYER) { if(atWar(m_pPlayer->getTeam(), GET_PLAYER(pAdjacentPlot->getOwner()).getTeam())) { ImprovementTypes eImprovement = pAdjacentPlot->getImprovementType(); if(eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0) { m_pPlots[iI].SetSubjectToAttack(true); break; } } } } } } } } } }