Hooks
static bool BeforeCvTacticalAI_FindBestBarbarianSeaMove(CvTacticalAI* self, UnitHandle pUnit, CvPlot*& result);static void AfterCvTacticalAI_FindBestBarbarianSeaMove(CvTacticalAI* self, UnitHandle pUnit, CvPlot*& result);static CvPlot* ReplaceCvTacticalAI_FindBestBarbarianSeaMove(CvPlot* (*original)(CvTacticalAI*, UnitHandle), CvTacticalAI* self, UnitHandle pUnit);CivRegisterBefore<CivHooks::CvTacticalAI_FindBestBarbarianSeaMove>(host, &BeforeCvTacticalAI_FindBestBarbarianSeaMove);CivRegisterAfter<CivHooks::CvTacticalAI_FindBestBarbarianSeaMove>(host, &AfterCvTacticalAI_FindBestBarbarianSeaMove);CivRegisterReplace<CivHooks::CvTacticalAI_FindBestBarbarianSeaMove>(host, &ReplaceCvTacticalAI_FindBestBarbarianSeaMove);
Code
10051/// Find a multi-turn target for a sea barbarian to wander towards10052CvPlot* CvTacticalAI::FindBestBarbarianSeaMove(UnitHandle pUnit)10053{10054 CvPlot* pBestMovePlot = NULL;10055 int iBestValue;10056 int iValue;10057 CvPlot* pPlot;10058 CvTacticalTarget* pTarget;10059 int iMovementRate;1006010061 iMovementRate = pUnit->baseMoves();10062 iBestValue = MAX_INT;10063 pBestMovePlot = NULL;1006410065 // Loop through all unit targets to find the closest10066 pTarget = GetFirstUnitTarget();10067 while(pTarget != NULL)10068 {10069 // Is this unit nearby enough?10070 if(plotDistance(pUnit->getX(), pUnit->getY(), pTarget->GetTargetX(), pTarget->GetTargetY()) < m_iSeaBarbarianRange)10071 {10072 pPlot = GC.getMap().plot(pTarget->GetTargetX(), pTarget->GetTargetY());10073#if defined(MOD_BUGFIX_MINOR)10074 if(pPlot && pUnit->getArea() == pPlot->getArea())10075#else10076 if(pUnit->getArea() == pPlot->getArea())10077#endif10078 {10079 iValue = TurnsToReachTarget(pUnit, pPlot, true /*bReusePaths*/);10080 if(iValue < iBestValue)10081 {10082 iBestValue = iValue;10083 pBestMovePlot = pPlot;10084 }10085 }10086 }10087 pTarget = GetNextUnitTarget();10088 }1008910090 // move toward trade routes10091 if (pBestMovePlot == NULL)10092 {10093 pBestMovePlot = FindBarbarianGankTradeRouteTarget(pUnit);10094 }1009510096 // No units to pick on, so sail to a tile adjacent to the second closest barbarian camp10097 if(pBestMovePlot == NULL)10098 {10099 CvPlot* pNearestCamp = NULL;10100 int iBestCampDistance = MAX_INT;1010110102 // Start by finding the very nearest camp10103 pTarget = GetFirstZoneTarget(AI_TACTICAL_TARGET_BARBARIAN_CAMP);10104 while(pTarget != NULL)10105 {10106 int iDistance = plotDistance(pUnit->getX(), pUnit->getY(), pTarget->GetTargetX(), pTarget->GetTargetY());10107 if(iDistance < iBestCampDistance)10108 {10109 pNearestCamp = GC.getMap().plot(pTarget->GetTargetX(), pTarget->GetTargetY());10110 iBestCampDistance = iDistance;10111 }10112 pTarget = GetNextZoneTarget();10113 }1011410115 // The obvious way to do this next part is to plot moves to each naval tile adjacent to each camp ...10116 // starting with the first camp and then proceeding to the final one. But our optimization (to drop out10117 // targets that are further from the closest we've found so far) might in worst case not help at all if we10118 // check the closest camp last. So instead we'll loop by DIRECTIONS first which should mean we pick up some plot10119 // from a close camp early (and the optimization will help)10120 for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++)10121 {10122 pTarget = GetFirstZoneTarget(AI_TACTICAL_TARGET_BARBARIAN_CAMP);10123 while(pTarget != NULL)10124 {10125 CvPlot* pCamp = GC.getMap().plot(pTarget->GetTargetX(), pTarget->GetTargetY());10126 if(pCamp != pNearestCamp)10127 {10128 pPlot = plotDirection(pCamp->getX(), pCamp->getY(), ((DirectionTypes)jJ));10129 if(pPlot && pPlot->isWater())10130 {10131 int iDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY());1013210133 // Optimization10134 if(iDistance < iMovementRate * iBestValue && iDistance < (m_iSeaBarbarianRange * 3))10135 {10136 iValue = TurnsToReachTarget(pUnit, pPlot, true /*bReusePaths*/);10137 if(iValue < iBestValue)10138 {10139 iBestValue = iValue;10140 pBestMovePlot = pPlot;10141 }10142 }10143 }10144 }10145 pTarget = GetNextZoneTarget();10146 }10147 }10148 }1014910150 // No obvious target, let's scan nearby tiles for the best choice, borrowing some of the code from the explore AI10151 if(pBestMovePlot == NULL)10152 {10153 // Now looking for BEST score10154 iBestValue = 0;10155 int iMovementRange = pUnit->movesLeft() / GC.getMOVE_DENOMINATOR();10156 for(int iX = -iMovementRange; iX <= iMovementRange; iX++)10157 {10158 for(int iY = -iMovementRange; iY <= iMovementRange; iY++)10159 {10160 CvPlot* pConsiderPlot = plotXYWithRangeCheck(pUnit->getX(), pUnit->getY(), iX, iY, iMovementRange);10161 if(!pConsiderPlot)10162 {10163 continue;10164 }1016510166 if(pUnit->atPlot(*pConsiderPlot))10167 {10168 continue;10169 }1017010171 if(!pConsiderPlot->isRevealed(pUnit->getTeam()))10172 {10173 continue;10174 }1017510176 if(pConsiderPlot->area() != pUnit->area())10177 {10178 continue;10179 }1018010181 if(!CanReachInXTurns(pUnit, pConsiderPlot, 1))10182 {10183 continue;10184 }1018510186 // Value them based on their explore value10187 DomainTypes eDomain = pUnit->getDomainType();10188 iValue = CvEconomicAI::ScoreExplorePlot(pConsiderPlot, pUnit->getTeam(), pUnit->getUnitInfo().GetBaseSightRange(), eDomain);1018910190 // Add special value for being near enemy lands10191 if(pConsiderPlot->isAdjacentOwned())10192 {10193 iValue += 100;10194 }10195 else if(pConsiderPlot->isOwned())10196 {10197 iValue += 200;10198 }1019910200 // If still have no value, score equal to distance from my current plot10201 if(iValue == 0)10202 {10203 iValue = plotDistance(pUnit->getX(), pUnit->getY(), pConsiderPlot->getX(), pConsiderPlot->getY());10204 }1020510206 if(iValue > iBestValue)10207 {10208 pBestMovePlot = pConsiderPlot;10209 iBestValue = iValue;10210 }10211 }10212 }10213 }1021410215 return pBestMovePlot;10216}