Code
7908/// Bombard an enemy target from a single plot we can protect from enemy attack (return true if some attack made)7909bool CvTacticalAI::ExecuteOneProtectedBombard(CvTacticalTarget& kTarget)7910{7911 UnitHandle pFirstAttacker;7912 int iDX, iDY;7913 CvPlot* pAttackPlot;7914 int iPlotIndex;7915 CvTacticalAnalysisCell* pCell;7916 int iPriority;7917 int iNumTurns;7918 int iNumUnitsRequiredToCover;79197920 CvPlot* pTargetPlot = GC.getMap().plot(kTarget.GetTargetX(), kTarget.GetTargetY());7921 if(PlotAlreadyTargeted(pTargetPlot) != -1)7922 {7923 return false;7924 }79257926 CvCity* pCity = pTargetPlot->getPlotCity();7927 if(pCity != NULL)7928 {7929 int iRequiredDamage = pCity->GetMaxHitPoints() - pCity->getDamage();79307931 // Can't eliminate a city with ranged fire, so don't target one if that low on health7932 if(iRequiredDamage <= 1)7933 {7934 return false;7935 }7936 }79377938 int iRange = m_pMap->GetBestFriendlyRange();7939 m_TempTargets.clear();79407941 // Build a list of all plots that have LOS to target where no enemy unit is adjacent7942 for(iDX = -(iRange); iDX <= iRange; iDX++)7943 {7944 for(iDY = -(iRange); iDY <= iRange; iDY++)7945 {7946 pAttackPlot = plotXY(kTarget.GetTargetX(), kTarget.GetTargetY(), iDX, iDY);7947 if(pAttackPlot != NULL)7948 {7949 int iPlotDistance = plotDistance(pAttackPlot->getX(), pAttackPlot->getY(), kTarget.GetTargetX(), kTarget.GetTargetY());7950 if(iPlotDistance > 0 && iPlotDistance <= iRange)7951 {7952 iPlotIndex = GC.getMap().plotNum(pAttackPlot->getX(), pAttackPlot->getY());7953 pCell = m_pMap->GetCell(iPlotIndex);7954 if(pCell->IsRevealed() && pCell->CanUseForOperationGathering())7955 {7956 if(pCell->IsWithinRangeOfTarget())7957 {7958 // Check for adjacent enemy unit7959 CvPlot* pLoopPlot;7960 bool bNoEnemyAdjacent = true;7961 for(int iI = 0; iI < NUM_DIRECTION_TYPES && bNoEnemyAdjacent; iI++)7962 {7963 pLoopPlot = plotDirection(pAttackPlot->getX(), pAttackPlot->getY(), ((DirectionTypes)iI));7964 if(pLoopPlot != NULL)7965 {7966 iPlotIndex = GC.getMap().plotNum(pLoopPlot->getX(), pLoopPlot->getY());7967 if(m_pMap->GetCell(iPlotIndex)->GetEnemyMilitaryUnit() != NULL)7968 {7969 bNoEnemyAdjacent = false;7970 }7971 }7972 }79737974 if(bNoEnemyAdjacent)7975 {7976 // Do we have a unit that can get off a bombard from here THIS turn7977 iNumTurns = -1;7978 bool bHaveLOS = pAttackPlot->canSeePlot(pTargetPlot, m_pPlayer->getTeam(), iRange, NO_DIRECTION);7979 if(FindClosestUnit(pAttackPlot, 0, false/*bMustHaveHalfHP*/, true /*bMustBeRangedUnit*/, iPlotDistance, !bHaveLOS, false/*bMustBeMeleeUnit*/, false/*bIgnoreUnits*/, pTargetPlot))7980 {7981 iNumTurns = 0;7982 }7983 // What about next turn?7984 else if(FindClosestUnit(pAttackPlot, 1, false/*bMustHaveHalfHP*/, true /*bMustBeRangedUnit*/, iPlotDistance, !bHaveLOS, false/*bMustBeMeleeUnit*/, false/*bIgnoreUnits*/, pTargetPlot))7985 {7986 iNumTurns = 1;7987 }79887989 // If found a unit that could get here, see if we can cover the hex from enemy attack7990 if(iNumTurns >= 0)7991 {7992 if(CanCoverFromEnemy(pAttackPlot, iNumUnitsRequiredToCover, m_CurrentMoveUnits[0].GetID()))7993 {7994 CvTacticalTarget target;7995 target.SetTargetX(pAttackPlot->getX());7996 target.SetTargetY(pAttackPlot->getY());79977998 // How desirable is this move?7999 // Set up math so having to allocate 3 extra units to defend is worse than waiting a turn to attack8000 iPriority = 300 - (iNumTurns * 100);8001 iPriority -= 40 * iNumUnitsRequiredToCover;8002 target.SetAuxIntData(iPriority);8003 m_TempTargets.push_back(target);8004 }8005 }8006 }8007 }8008 }8009 }8010 }8011 }8012 }80138014 // No plots to shoot from?8015 if(m_TempTargets.size() == 0)8016 {8017 return false;8018 }80198020 // Sort potential spots8021 std::stable_sort(m_TempTargets.begin(), m_TempTargets.end());80228023 // Have to rebuild blocking position info for this specific spot8024 pAttackPlot = GC.getMap().plot(m_TempTargets[0].GetTargetX(), m_TempTargets[0].GetTargetY());8025 int iPlotDistance = plotDistance(pAttackPlot->getX(), pAttackPlot->getY(), kTarget.GetTargetX(), kTarget.GetTargetY());8026 bool bHaveLOS = pAttackPlot->canSeePlot(pTargetPlot, m_pPlayer->getTeam(), iRange, NO_DIRECTION);8027 if(FindClosestUnit(pAttackPlot, 0, false/*bMustHaveHalfHP*/, true /*bMustBeRangedUnit*/, iPlotDistance, !bHaveLOS, false/*bMustBeMeleeUnit*/, false/*bIgnoreUnits*/, pTargetPlot) ||8028 FindClosestUnit(pAttackPlot, 1, false/*bMustHaveHalfHP*/, true /*bMustBeRangedUnit*/, iPlotDistance, !bHaveLOS, false/*bMustBeMeleeUnit*/, false/*bIgnoreUnits*/, pTargetPlot))8029 {8030 int iAttackingUnitID = m_CurrentMoveUnits[0].GetID();8031 if(pAttackPlot && CanCoverFromEnemy(pAttackPlot, iNumUnitsRequiredToCover, iAttackingUnitID))8032 {8033 // Make each blocking move8034 for(unsigned int iI = 0; iI < m_ChosenBlocks.size(); iI++)8035 {8036 CvUnit* pChosenUnit = m_pPlayer->getUnit(m_ChosenBlocks[iI].GetUnitID());8037 if(pChosenUnit)8038 {8039 if (pChosenUnit->plot() != m_ChosenBlocks[iI].GetPlot())8040 {8041 if(GC.getLogging() && GC.getAILogging())8042 {8043 CvString strMsg;8044 strMsg.Format("Moving to cover a protected bombard with %s, X: %d, Y: %d", pChosenUnit->getName().GetCString(),8045 m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8046 LogTacticalMessage(strMsg, false);8047 }8048 pChosenUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8049 }8050 else if (pChosenUnit->canPillage(pChosenUnit->plot()) && pChosenUnit->getDamage() > 0)8051 {8052 pChosenUnit->PushMission(CvTypes::getMISSION_PILLAGE());8053 if(GC.getLogging() && GC.getAILogging())8054 {8055 CvString strMsg;8056 strMsg.Format("Pillaging during a protected bombard with %s, X: %d, Y: %d", pChosenUnit->getName().GetCString(),8057 m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8058 LogTacticalMessage(strMsg, false);8059 }8060 }8061 else if(pChosenUnit->canFortify(pChosenUnit->plot()))8062 {8063 pChosenUnit->PushMission(CvTypes::getMISSION_FORTIFY());8064 if(GC.getLogging() && GC.getAILogging())8065 {8066 CvString strMsg;8067 strMsg.Format("Fortifying during a protected bombard with %s, X: %d, Y: %d", pChosenUnit->getName().GetCString(),8068 m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8069 LogTacticalMessage(strMsg, false);8070 }8071 }8072 else8073 {8074 if(GC.getLogging() && GC.getAILogging())8075 {8076 CvString strMsg;8077 strMsg.Format("Sitting during a protected bombard with %s, X: %d, Y: %d", pChosenUnit->getName().GetCString(),8078 m_ChosenBlocks[iI].GetPlot()->getX(), m_ChosenBlocks[iI].GetPlot()->getY());8079 LogTacticalMessage(strMsg, false);8080 }8081 }8082 pChosenUnit->finishMoves();8083 UnitProcessed(pChosenUnit->GetID());8084 }8085 }80868087 // Then move the attacking unit8088 CvUnit* pUnit = m_pPlayer->getUnit(iAttackingUnitID);8089 if(pUnit)8090 {8091 if(pAttackPlot != pUnit->plot())8092 {8093 pUnit->PushMission(CvTypes::getMISSION_MOVE_TO(), pAttackPlot->getX(), pAttackPlot->getY());80948095 if(GC.getLogging() && GC.getAILogging())8096 {8097 CvString strMsg;8098 strMsg.Format("Moving closer for protected bombard with %s, Target X: %d, Target Y: %d, At X: %d, At Y: %d", pUnit->getName().GetCString(),8099 pAttackPlot->getX(), pAttackPlot->getY(), pUnit->getX(), pUnit->getY());8100 LogTacticalMessage(strMsg, false);8101 }8102 }81038104#if defined(MOD_AI_SMART_V3)8105 if (!MOD_AI_SMART_V3)8106#endif8107 UnitProcessed(iAttackingUnitID);81088109 if(pUnit->canSetUpForRangedAttack(NULL))8110 {8111 pUnit->setSetUpForRangedAttack(true);8112 if(GC.getLogging() && GC.getAILogging())8113 {8114 CvString strMsg;8115 strMsg.Format("Set up %s for ranged attack", pUnit->getName().GetCString());8116 LogTacticalMessage(strMsg, false);8117 }8118 }81198120 if(pUnit->canMove() && !pUnit->isOutOfAttacks() && pUnit->canRangeStrikeAt(kTarget.GetTargetX(), kTarget.GetTargetY()))8121 {8122 if(GC.getLogging() && GC.getAILogging())8123 {8124 CvString strMsg;8125 strMsg.Format("Making a protected bombard with %s, Target X: %d, Target Y: %d, At X: %d, At Y: %d", pUnit->getName().GetCString(),8126 kTarget.GetTargetX(), kTarget.GetTargetY(), pUnit->getX(), pUnit->getY());8127 LogTacticalMessage(strMsg, false);8128 }81298130 if(QueueAttack((void*)pUnit, &kTarget, true /*bRanged*/, false /*bCityAttack*/))8131 {8132 pFirstAttacker = pUnit;8133 }8134 }8135 8136#if defined(MOD_AI_SMART_V3)8137 if (MOD_AI_SMART_V3)8138 UnitProcessed(iAttackingUnitID);8139#endif8140 }8141 }81428143 if(pFirstAttacker)8144 {8145 LaunchAttack((void*)pFirstAttacker.pointer(), &kTarget, true /*bFirst*/, true /*bFirstAttackRanged*/, false /*bCityAttack*/);8146 return true;8147 }8148 }81498150 return false;8151}