// Mark cells we can use to bomb a specific target void CvTacticalAnalysisMap::SetTargetBombardCells(CvPlot* pTarget, int iRange, bool bIgnoreLOS) { int iDX, iDY; CvPlot* pLoopPlot; int iPlotIndex; int iPlotDistance; for(iDX = -(iRange); iDX <= iRange; iDX++) { for(iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(pTarget->getX(), pTarget->getY(), iDX, iDY); if(pLoopPlot != NULL) { iPlotDistance = plotDistance(pLoopPlot->getX(), pLoopPlot->getY(), pTarget->getX(), pTarget->getY()); if(iPlotDistance > 0 && iPlotDistance <= iRange) { iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY()); if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory()) { if(!m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity()) { if(bIgnoreLOS || pLoopPlot->canSeePlot(pTarget, m_pPlayer->getTeam(), iRange, NO_DIRECTION)) { m_pPlots[iPlotIndex].SetWithinRangeOfTarget(true); } } } } } } } }
/// 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].clear(); } //units we know from last turn UnitSet previousKnownUnits = m_knownUnits; m_knownUnits.clear(); 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)) { UpdateDangerSingleUnit(pLoopUnit, bIgnoreVisibility, true); } // for each city CvCity* pLoopCity; for(pLoopCity = loopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = loopPlayer.nextCity(&iLoop)) { if(ShouldIgnoreCity(pLoopCity, bIgnoreVisibility)) continue; #if defined(MOD_EVENTS_CITY_BOMBARD) bool bIndirectFireAllowed = false; int iRange = pLoopCity->getBombardRange(bIndirectFireAllowed); #else int iRange = GC.getCITY_ATTACK_RANGE(); #endif CvPlot* pCityPlot = pLoopCity->plot(); 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 || pLoopPlot == pCityPlot) continue; #if defined(MOD_EVENTS_CITY_BOMBARD) if (!bIndirectFireAllowed && !pCityPlot->canSeePlot(pLoopPlot, NO_TEAM, iRange, NO_DIRECTION)) continue; #endif AssignCityDangerValue(pLoopCity, pLoopPlot); } } } } // now compare the new known units with the previous known units for (UnitSet::iterator it = previousKnownUnits.begin(); it != previousKnownUnits.end(); ++it) { //might have made peace ... if (ShouldIgnorePlayer(it->first)) continue; if (m_knownUnits.find(*it) == m_knownUnits.end()) { CvUnit* pVanishedUnit = GET_PLAYER(it->first).getUnit(it->second); //it's still there, but moved out of sight - nevertheless count is, a human would do that as well //do not add it to the known units though, so next turn we will have forgotten about it if (pVanishedUnit) UpdateDangerSingleUnit(pVanishedUnit, true, false); } } int iPlotLoop; CvPlot* pPlot, *pAdjacentPlot; for(iPlotLoop = 0; iPlotLoop < GC.getMap().numPlots(); iPlotLoop++) { pPlot = GC.getMap().plotByIndexUnchecked(iPlotLoop); if(pPlot->isRevealed(thisTeam)) { //remember the plot based damage, but it depends on the unit's promotions also, so we won't apply it directly int iPlotDamage = 0; if (pPlot->getFeatureType() != NO_FEATURE) iPlotDamage += (GC.getFeatureInfo(pPlot->getFeatureType())->getTurnDamage()); if (pPlot->getTerrainType() != NO_FEATURE) iPlotDamage += (GC.getTerrainInfo(pPlot->getTerrainType())->getTurnDamage()); m_DangerPlots[iPlotLoop].m_bFlatPlotDamage = (iPlotDamage>0); 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) { m_DangerPlots[iPlotLoop].m_pCitadel = pPlot; } } } } } } // testing city danger values CvCity* pLoopCity; int iLoopCity = 0; for(pLoopCity = thisPlayer.firstCity(&iLoopCity); pLoopCity != NULL; pLoopCity = thisPlayer.nextCity(&iLoopCity)) { //adding danger would count each unit multiple times, is biased towards fast units //so we pretend they would all attack the city and tally up the damage //question is, what about our own defensive units in the area. should we count those as well? int iEvalRange = 4; int iThreatValue = 0; for(int iX = -iEvalRange; iX <= iEvalRange; iX++) for(int iY = -iEvalRange; iY <= iEvalRange; iY++) { CvPlot* pEvalPlot = plotXYWithRangeCheck(pLoopCity->getX(), pLoopCity->getY(), iX, iY, iEvalRange); if (pEvalPlot) { const CvUnit* pEnemy = pEvalPlot->getBestDefender(NO_PLAYER, thisPlayer.GetID(), NULL, true); if (pEnemy) { int iAttackerDamage = 0; //to be ignored iThreatValue += TacticalAIHelpers::GetSimulatedDamageFromAttackOnCity(pLoopCity,pEnemy,iAttackerDamage); } } } pLoopCity->SetThreatValue(iThreatValue); } m_bDirty = false; }
// Mark cells we can use to bomb a specific target void CvTacticalAnalysisMap::SetTargetBombardCells(CvPlot* pTarget, int iRange, bool bIgnoreLOS) { int iDX, iDY; CvPlot* pLoopPlot; int iPlotIndex; #ifdef AUI_HEXSPACE_DX_LOOPS int iMaxDX; for (iDY = -iRange; iDY <= iRange; iDY++) { iMaxDX = iRange - MAX(0, iDY); for (iDX = -iRange - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!) #else int iPlotDistance; for(iDX = -(iRange); iDX <= iRange; iDX++) { for(iDY = -(iRange); iDY <= iRange; iDY++) #endif { #ifdef AUI_HEXSPACE_DX_LOOPS if (iDX == 0 && iDY == 0) continue; #endif pLoopPlot = plotXY(pTarget->getX(), pTarget->getY(), iDX, iDY); if(pLoopPlot != NULL) { #ifndef AUI_HEXSPACE_DX_LOOPS #ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE iPlotDistance = hexDistance(iDX, iDY); #else iPlotDistance = plotDistance(pLoopPlot->getX(), pLoopPlot->getY(), pTarget->getX(), pTarget->getY()); #endif if(iPlotDistance > 0 && iPlotDistance <= iRange) #endif { iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY()); if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory()) { if(!m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity()) { if(bIgnoreLOS || pLoopPlot->canSeePlot(pTarget, m_pPlayer->getTeam(), iRange, NO_DIRECTION)) { m_pPlots[iPlotIndex].SetWithinRangeOfTarget(true); } } } } } } } } // Mark cells we can use to bomb a specific target void CvTacticalAnalysisMap::SetTargetFlankBonusCells(CvPlot* pTarget) { CvPlot* pLoopPlot; int iPlotIndex; // No flank attacks on units at sea (where all combat is bombards) if(pTarget->isWater()) { return; } for(int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pLoopPlot = plotDirection(pTarget->getX(), pTarget->getY(), ((DirectionTypes)iI)); if(pLoopPlot != NULL) { iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY()); if(m_pPlots[iPlotIndex].IsRevealed() && !m_pPlots[iPlotIndex].IsImpassableTerrain() && !m_pPlots[iPlotIndex].IsImpassableTerritory()) { if(!m_pPlots[iPlotIndex].IsFriendlyCity() && !m_pPlots[iPlotIndex].IsEnemyCity() && !m_pPlots[iPlotIndex].IsNeutralCity()) { if(!m_pPlots[iPlotIndex].IsFriendlyTurnEndTile() && m_pPlots[iPlotIndex].GetEnemyMilitaryUnit() == NULL) { m_pPlots[iPlotIndex].SetHelpsProvidesFlankBonus(true); } } } } } }