diff --git a/CvGameCoreDLL_Expansion2/CvAIOperation.cpp b/CvGameCoreDLL_Expansion2/CvAIOperation.cpp index 4e295c58ad..0e335ec62c 100644 --- a/CvGameCoreDLL_Expansion2/CvAIOperation.cpp +++ b/CvGameCoreDLL_Expansion2/CvAIOperation.cpp @@ -1615,7 +1615,7 @@ bool CvAIOperationMilitary::CheckTransitionToNextStage() int nVisible = 0; for (CvUnit* pUnit = pThisArmy->GetFirstUnit(); pUnit; pUnit = pThisArmy->GetNextUnit(pUnit)) { - if (pUnit->plot()->isVisible( GET_PLAYER(m_eEnemy).getTeam() )) + if (GET_PLAYER(pUnit->getOwner()).GetTacticalAI()->IsVisibleToPlayer(pUnit->plot(), GET_PLAYER(m_eEnemy).getTeam())) nVisible++; } diff --git a/CvGameCoreDLL_Expansion2/CvAStar.cpp b/CvGameCoreDLL_Expansion2/CvAStar.cpp index 9ba2979670..cea8d26a04 100644 --- a/CvGameCoreDLL_Expansion2/CvAStar.cpp +++ b/CvGameCoreDLL_Expansion2/CvAStar.cpp @@ -2184,7 +2184,7 @@ int CityConnectionWaterValid(const CvAStarNode* parent, const CvAStarNode* node, // -------------------------------------------------------------------------------- /// Prefer building routes that can have villages. -int BuildRouteVillageBonus(CvPlayer* pPlayer, CvPlot* pPlot, RouteTypes eRouteType, CvBuilderTaskingAI* eBuilderTaskingAi) +static int BuildRouteVillageBonus(CvPlayer* pPlayer, CvPlot* pPlot, RouteTypes eRouteType, CvBuilderTaskingAI* eBuilderTaskingAi) { // If we're not the owner of this plot, bail out if (!pPlot->isOwned() || pPlot->getOwner() != pPlayer->GetID()) @@ -2239,9 +2239,6 @@ int BuildRouteVillageBonus(CvPlayer* pPlayer, CvPlot* pPlot, RouteTypes eRouteTy if (pkImprovementInfo == NULL) continue; - if (pkImprovementInfo->IsCreatedByGreatPerson()) - continue; - for (int iYield = 0; iYield < NUM_YIELD_TYPES; iYield++) { YieldTypes eYield = (YieldTypes)iYield; @@ -2289,10 +2286,10 @@ int BuildRouteCost(const CvAStarNode* /*parent*/, const CvAStarNode* node, const } //too dangerous, might be severed any time - if (pPlot->getOwner() == NO_PLAYER && pPlot->IsAdjacentOwnedByTeamOtherThan(pPlayer->getTeam())) + if (pPlot->getOwner() == NO_PLAYER && pPlot->IsAdjacentOwnedByTeamOtherThan(pPlayer->getTeam(), false, false, true, true)) iCost *= 3; - if (data.bIsForCapital) + if (data.bBenefitsVillages) iCost -= BuildRouteVillageBonus(pPlayer, pPlot, eRouteType, eBuilderTaskingAi); if (iCost < 0) @@ -2301,26 +2298,38 @@ int BuildRouteCost(const CvAStarNode* /*parent*/, const CvAStarNode* node, const return iCost; } -bool IsSafeForRoute(CvPlot* pPlot, CvPlayer* ePlayer) +static bool IsSafeForRoute(CvPlot* pPlot, CvPlayer* pPlayer) { + TeamTypes ePlotTeam = pPlot->getTeam(); + TeamTypes ePlayerTeam = pPlayer->getTeam(); + PlayerTypes ePlotOwner = pPlot->getOwner(); + // Our plots and surrounding plots are safe - if (pPlot->getTeam() == ePlayer->getTeam() || pPlot->isAdjacentTeam(ePlayer->getTeam(), false)) + if (ePlotTeam == ePlayerTeam || pPlot->isAdjacentTeam(pPlayer->getTeam(), false)) + { + return true; + } + + // Our vassal's plots and surrounding plots are safe + if (GET_TEAM(ePlotTeam).IsVassal(ePlayerTeam) || pPlot->isAdjacentOwnedByVassal(ePlayerTeam, false)) { return true; } // City state plots and surrounding plots are safe - if (pPlot->isOwned() && GET_PLAYER(pPlot->getOwner()).isMinorCiv() && !GET_PLAYER(pPlot->getOwner()).GetMinorCivAI()->IsAtWarWithPlayersTeam(ePlayer->GetID())) + if (ePlotOwner != NO_PLAYER && GET_PLAYER(ePlotOwner).isMinorCiv() && !GET_PLAYER(ePlotOwner).GetMinorCivAI()->IsAtWarWithPlayersTeam(pPlayer->GetID())) { return true; } CvPlot** aPlotsToCheck = GC.getMap().getNeighborsUnchecked(pPlot); + PlayerTypes eAdjacentOwner; for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { CvPlot* pAdjacentPlot = aPlotsToCheck[iI]; if (pAdjacentPlot != NULL) { - if (pAdjacentPlot->isOwned() && GET_PLAYER(pAdjacentPlot->getOwner()).isMinorCiv() && !GET_PLAYER(pAdjacentPlot->getOwner()).GetMinorCivAI()->IsAtWarWithPlayersTeam(ePlayer->GetID())) + eAdjacentOwner = pAdjacentPlot->getOwner(); + if (eAdjacentOwner != NO_PLAYER && GET_PLAYER(eAdjacentOwner).isMinorCiv() && !GET_PLAYER(eAdjacentOwner).GetMinorCivAI()->IsAtWarWithPlayersTeam(pPlayer->GetID())) { return true; } @@ -2357,7 +2366,7 @@ int BuildRouteValid(const CvAStarNode* parent, const CvAStarNode* node, const SP return FALSE; PlayerTypes ePlotOwnerPlayer = pNewPlot->getOwner(); - if(ePlotOwnerPlayer != NO_PLAYER && pNewPlot->getTeam() != thisPlayer.getTeam()) + if(ePlotOwnerPlayer != NO_PLAYER && pNewPlot->getTeam() != thisPlayer.getTeam() && !GET_TEAM(pNewPlot->getTeam()).IsVassal(thisPlayer.getTeam())) { PlayerTypes eMajorPlayer = NO_PLAYER; PlayerTypes eMinorPlayer = NO_PLAYER; @@ -2376,11 +2385,6 @@ int BuildRouteValid(const CvAStarNode* parent, const CvAStarNode* node, const SP { return FALSE; } - - if(!GET_PLAYER(eMinorPlayer).GetMinorCivAI()->IsActiveQuestForPlayer(eMajorPlayer, MINOR_CIV_QUEST_ROUTE)) - { - return FALSE; - } } //Free routes from traits are always safe @@ -3715,7 +3719,7 @@ SPathFinderUserData::SPathFinderUserData(const CvUnit* pUnit, int _iFlags, int _ iMaxNormalizedDistance = INT_MAX; iMinMovesLeft = 0; iStartMoves = pUnit ? pUnit->getMoves() : 0; - bIsForCapital = false; + bBenefitsVillages = false; } // --------------------------------------------------------------------------- @@ -3733,7 +3737,7 @@ SPathFinderUserData::SPathFinderUserData(PlayerTypes _ePlayer, PathType _ePathTy iMaxNormalizedDistance = INT_MAX; iMinMovesLeft = 0; iStartMoves = 0; - bIsForCapital = false; + bBenefitsVillages = false; } // --------------------------------------------------------------------------- @@ -3751,7 +3755,7 @@ SPathFinderUserData::SPathFinderUserData(PlayerTypes _ePlayer, PathType _ePathTy iMaxNormalizedDistance = INT_MAX; iMinMovesLeft = 0; iStartMoves = 0; - bIsForCapital = false; + bBenefitsVillages = false; } // --------------------------------------------------------------------------- @@ -3769,12 +3773,12 @@ SPathFinderUserData::SPathFinderUserData(PlayerTypes _ePlayer, PathType _ePathTy iMaxNormalizedDistance = INT_MAX; iMinMovesLeft = 0; iStartMoves = 0; - bIsForCapital = false; + bBenefitsVillages = false; } // --------------------------------------------------------------------------- //convenience constructor -SPathFinderUserData::SPathFinderUserData(PlayerTypes _ePlayer, PathType _ePathType, BuildTypes _eBuildType, RouteTypes _eRouteType, bool _bIsForCapital) +SPathFinderUserData::SPathFinderUserData(PlayerTypes _ePlayer, PathType _ePathType, BuildTypes _eBuildType, RouteTypes _eRouteType, bool _bBenefitsVillages) { ePathType = _ePathType; iFlags = 0; @@ -3787,7 +3791,7 @@ SPathFinderUserData::SPathFinderUserData(PlayerTypes _ePlayer, PathType _ePathTy iMaxNormalizedDistance = INT_MAX; iMinMovesLeft = 0; iStartMoves = 0; - bIsForCapital = _bIsForCapital; + bBenefitsVillages = _bBenefitsVillages; } CvPlot * SPath::get(int i) const diff --git a/CvGameCoreDLL_Expansion2/CvAStarNode.h b/CvGameCoreDLL_Expansion2/CvAStarNode.h index 9888ffd674..c13f9c2d40 100644 --- a/CvGameCoreDLL_Expansion2/CvAStarNode.h +++ b/CvGameCoreDLL_Expansion2/CvAStarNode.h @@ -136,12 +136,12 @@ class CvAStarNode //------------------------------------------------------------------------------------------------- struct SPathFinderUserData { - SPathFinderUserData() : ePathType(PT_GENERIC_SAME_AREA), iFlags(0), ePlayer(NO_PLAYER), eEnemy(NO_PLAYER), iUnitID(0), eBuildType(NO_BUILD), eRouteType(NO_ROUTE), bIsForCapital(false), iMaxTurns(INT_MAX), iMaxNormalizedDistance(INT_MAX), iMinMovesLeft(0), iStartMoves(60) {} + SPathFinderUserData() : ePathType(PT_GENERIC_SAME_AREA), iFlags(0), ePlayer(NO_PLAYER), eEnemy(NO_PLAYER), iUnitID(0), eBuildType(NO_BUILD), eRouteType(NO_ROUTE), bBenefitsVillages(false), iMaxTurns(INT_MAX), iMaxNormalizedDistance(INT_MAX), iMinMovesLeft(0), iStartMoves(60) {} SPathFinderUserData(const CvUnit* pUnit, int iFlags=0, int iMaxTurns=INT_MAX); // PT_AIR_REBASE (special case, set after construction) SPathFinderUserData(PlayerTypes ePlayer, PathType ePathType); // PT_TRADE_WATER, PT_TRADE_LAND, PT_LANDMASS_CONNECTION, PT_CITY_CONNECTION_WATER SPathFinderUserData(PlayerTypes ePlayer, PathType ePathType, int iMaxTurns); // PT_AREA_CONNECTION (iMaxTurns is simple vs complex check (0/1)), PT_CITY_INFLUENCE SPathFinderUserData(PlayerTypes ePlayer, PathType ePathType, PlayerTypes eEnemy, int iMaxTurns); // PT_GENERIC_SAME_AREA, PT_GENERIC_SAME_AREA_WIDE, PT_ARMY_LAND, PT_ARMY_WATER, PT_ARMY_MIXED - SPathFinderUserData(PlayerTypes ePlayer, PathType ePathType, BuildTypes eBuildType, RouteTypes eRouteType, bool bIsForCapital); // PT_BUILD_ROUTE, PT_BUILD_ROUTE_MIXED, PT_CITY_CONNECTION_LAND, PT_CITY_CONNECTION_MIXED + SPathFinderUserData(PlayerTypes ePlayer, PathType ePathType, BuildTypes eBuildType, RouteTypes eRouteType, bool bBenefitsVillages); // PT_BUILD_ROUTE, PT_BUILD_ROUTE_MIXED, PT_CITY_CONNECTION_LAND, PT_CITY_CONNECTION_MIXED //do not compare max turns and max cost ... bool operator==(const SPathFinderUserData& rhs) const @@ -151,7 +151,7 @@ struct SPathFinderUserData PathType ePathType; RouteTypes eRouteType; BuildTypes eBuildType; //BuildType related to the RouteType - bool bIsForCapital; + bool bBenefitsVillages; int iFlags; //see CvUnit::MOVEFLAG* PlayerTypes ePlayer; //optional PlayerTypes eEnemy; diff --git a/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.cpp b/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.cpp index 6dce2368d9..681b3129f1 100644 --- a/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.cpp +++ b/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.cpp @@ -41,7 +41,6 @@ void CvBuilderTaskingAI::Init(CvPlayer* pPlayer) m_eFalloutFeature = GetFalloutFeature(); m_eFalloutRemove = GetFalloutRemove(); m_eRemoveRouteBuild = GetRemoveRoute(); - m_eRouteBuild = NO_BUILD; //will be updated each turn! m_bLogging = GC.getLogging() && GC.getAILogging() && GC.GetBuilderAILogging(); @@ -200,8 +199,6 @@ void CvBuilderTaskingAI::Update(void) UpdateRoutePlots(); UpdateCanalPlots(); - m_eRouteBuild = GetBuildRoute(); - if(m_bLogging) { bool bShowOutput = m_pPlayer->isHuman(); @@ -260,7 +257,7 @@ int GetPlotYield(CvPlot* pPlot, YieldTypes eYield) return pPlot->calculateNatureYield(eYield, NO_PLAYER, NULL); } -void CvBuilderTaskingAI::ConnectCitiesToCapital(CvCity* pPlayerCapital, CvCity* pTargetCity, BuildTypes eBuild, RouteTypes eRoute, int iNetGoldTimes100) +void CvBuilderTaskingAI::ConnectCitiesToCapital(CvCity* pPlayerCapital, CvCity* pTargetCity, BuildTypes eBuild, RouteTypes eRoute) { if(pTargetCity->IsRazing()) { @@ -289,12 +286,16 @@ void CvBuilderTaskingAI::ConnectCitiesToCapital(CvCity* pPlayerCapital, CvCity* } // for quests we might be targeting a city state ... - bool bSamePlayer = pTargetCity->getOwner() == pPlayerCapital->getOwner(); + bool bTargetingMinor = GET_TEAM(pTargetCity->getTeam()).isMinorCiv(); + + // There's no reason for building railroads for city state quests + if (bTargetingMinor && eRoute == ROUTE_RAILROAD) + return; bool bHuman = m_pPlayer->isHuman(); // go through the route to see how long it is and how many plots already have roads int iRoadLength = 0; - int iPlotsNeeded = 0; + int iRoadMaintenanceLength = 0; for (size_t i=0; igetOwner() != pCity2->getOwner()) return; - // don't build shortcut routes when we are losing money - if (iNetGoldTimes100 < 0) - return; - // don't connect razing cities if (pCity1->IsRazing() || pCity2->IsRazing()) return; @@ -413,7 +410,7 @@ void CvBuilderTaskingAI::ConnectCitiesForShortcuts(CvCity* pCity1, CvCity* pCity } // build a path between the two cities - this will tend to re-use existing routes, unless the new path is much shorter - SPathFinderUserData data(m_pPlayer->GetID(),PT_BUILD_ROUTE,eBuild,eRoute,false); + SPathFinderUserData data(m_pPlayer->GetID(),PT_BUILD_ROUTE,eBuild,eRoute,true); SPath newPath = GC.GetStepFinder().GetPath(pCity1->getX(), pCity1->getY(), pCity2->getX(), pCity2->getY(), data); // cities are not on the same landmass? then give up @@ -422,7 +419,7 @@ void CvBuilderTaskingAI::ConnectCitiesForShortcuts(CvCity* pCity1, CvCity* pCity // go through the route to see how long it is and how many plots already have roads int iRoadLength = 0; - int iPlotsNeeded = 0; + int iRoadMaintenanceLength = 0; for (size_t i = 0; i < newPath.vPlots.size(); i++) { @@ -442,8 +439,8 @@ void CvBuilderTaskingAI::ConnectCitiesForShortcuts(CvCity* pCity1, CvCity* pCity iRoadLength++; - if ((pPlot->getRouteType() < eRoute || pPlot->IsRoutePillaged()) && !GetSameRouteBenefitFromTrait(pPlot, eRoute)) - iPlotsNeeded++; + if (!GetSameRouteBenefitFromTrait(pPlot, eRoute)) + iRoadMaintenanceLength++; } int iMaintenancePerTile = pRouteInfo->GetGoldMaintenance() * (100 + m_pPlayer->GetImprovementGoldMaintenanceMod()); @@ -457,9 +454,9 @@ void CvBuilderTaskingAI::ConnectCitiesForShortcuts(CvCity* pCity1, CvCity* pCity iSideBenefits += iRoadLength * 150; } - int iProfit = iSideBenefits - (iRoadLength * iMaintenancePerTile); + int iProfit = iSideBenefits - (iRoadMaintenanceLength * iMaintenancePerTile); - if (iProfit < 0 && iProfit + iNetGoldTimes100 < 0) + if (iProfit < 0) return; for (size_t i=0; iGetCityConnections(); + m_routeNeededPlots.clear(); + m_routeWantedPlots.clear(); + m_mainRoutePlots.clear(); + m_shortcutRoutePlots.clear(); + m_strategicRoutePlots.clear(); + // if there are fewer than 2 cities, we don't need to run this function std::vector plotsToConnect = pCityConnections->GetPlotsToConnect(); if(plotsToConnect.size() < 2) @@ -779,12 +782,6 @@ void CvBuilderTaskingAI::UpdateRoutePlots(void) return; } - m_routeNeededPlots.clear(); - m_routeWantedPlots.clear(); - m_mainRoutePlots.clear(); - m_shortcutRoutePlots.clear(); - m_strategicRoutePlots.clear(); - for(int i = GC.getNumBuildInfos() - 1; i >= 0; i--) { BuildTypes eBuild = (BuildTypes)i; @@ -859,7 +856,7 @@ void CvBuilderTaskingAI::UpdateRoutePlots(void) { //if we already have a connection to the capital, it may be possible to have a much shorter route for a direct connection //thus improving unit movement and gold bonus from villages - ConnectCitiesForShortcuts(pFirstCity, pSecondCity, eBuild, eRoute, iNetGoldTimes100); + ConnectCitiesForShortcuts(pFirstCity, pSecondCity, eBuild, eRoute); } else { @@ -874,7 +871,7 @@ void CvBuilderTaskingAI::UpdateRoutePlots(void) pTargetCity = pFirstCity; } - ConnectCitiesToCapital(pPlayerCapitalCity, pTargetCity, eBuild, eRoute, iNetGoldTimes100); + ConnectCitiesToCapital(pPlayerCapitalCity, pTargetCity, eBuild, eRoute); } } else @@ -1522,22 +1519,25 @@ void CvBuilderTaskingAI::AddRemoveRouteDirectives(vectorgetBestRoute(); - if (eBestRouteType == NO_ROUTE) + if (m_pPlayer->getBestRoute() == NO_ROUTE) return; - if (pPlot->getRouteType() == NO_ROUTE) + RouteTypes eRoute = pPlot->getRouteType(); + + if (eRoute == NO_ROUTE) return; if (pPlot->isCity()) return; + RouteTypes eWantedRoute = GetRouteTypeWantedAtPlot(pPlot); + // the plot was flagged recently, so ignore - if (WantRouteAtPlot(pPlot)) + if (eWantedRoute >= eRoute) return; // keep routes which are needed - if (NeedRouteAtPlot(pPlot) && !GetSameRouteBenefitFromTrait(pPlot, pPlot->getRouteType())) + if (GetRouteTypeNeededAtPlot(pPlot) >= eRoute && !GetSameRouteBenefitFromTrait(pPlot, eWantedRoute)) { return; } @@ -1546,22 +1546,22 @@ void CvBuilderTaskingAI::AddRemoveRouteDirectives(vectorIsRoutePillaged()) return; - // don't remove routes which we did not create - if (pPlot->GetPlayerResponsibleForRoute() != NO_PLAYER && pPlot->GetPlayerResponsibleForRoute() != m_pPlayer->GetID()) + // don't remove routes which we do not pay maintenance for + PlayerTypes eRouteResponsible = pPlot->GetPlayerResponsibleForRoute(); + if (eRouteResponsible != m_pPlayer->GetID()) return; - //don't touch master's roads! - if (pPlot->GetPlayerResponsibleForRoute() != NO_PLAYER && pPlot->GetPlayerResponsibleForRoute() != m_pPlayer->GetID()) - if (GET_TEAM(m_pPlayer->getTeam()).IsVassal(GET_PLAYER(pPlot->GetPlayerResponsibleForRoute()).getTeam())) - return; + // don't remove routes that we pay maintenance for if our master built them + if (eRouteResponsible == m_pPlayer->GetID() && GET_TEAM(m_pPlayer->getTeam()).IsVassal(GET_PLAYER(pPlot->GetPlayerThatBuiltRoute()).getTeam())) + return; //we want to be aggressive with this because of the cost. - int iWeight = /*500*/ GD_INT_GET(BUILDER_TASKING_BASELINE_BUILD_ROUTES) * 2 / 3; + int iWeight = /*500*/ GD_INT_GET(BUILDER_TASKING_BASELINE_BUILD_ROUTES) * 2; //if we are in debt, be more aggressive EconomicAIStrategyTypes eStrategyLosingMoney = (EconomicAIStrategyTypes)GC.getInfoTypeForString("ECONOMICAISTRATEGY_LOSING_MONEY"); - if (!m_pPlayer->GetEconomicAI()->IsUsingStrategy(eStrategyLosingMoney)) - iWeight *= 2; + if (m_pPlayer->GetEconomicAI()->IsUsingStrategy(eStrategyLosingMoney)) + iWeight *= 3; iWeight = GetBuildCostWeight(iWeight, pPlot, m_eRemoveRouteBuild); iWeight += GetBuildTimeWeight(pUnit, pPlot, m_eRemoveRouteBuild, false); @@ -1597,22 +1597,23 @@ void CvBuilderTaskingAI::AddRemoveRouteDirectives(vector>& directives, CvUnit* pUnit, CvPlot* pPlot, CvCity* /*pCity*/, int iMoveTurnsAway) { - // if the player can't build a route, bail out! - RouteTypes eBestRouteType = m_pPlayer->getBestRoute(); - if(eBestRouteType == NO_ROUTE) + // the plot was not flagged recently, so ignore + if (!WantRouteAtPlot(pPlot)) return; + RouteTypes eRoute = GetRouteTypeWantedAtPlot(pPlot); + if(eRoute == NO_ROUTE) + return; + + BuildTypes eRouteBuild = GetBuildRoute(eRoute); + // can we even build the desired route CvUnitEntry& kUnitInfo = pUnit->getUnitInfo(); - if(m_eRouteBuild == NO_BUILD || !kUnitInfo.GetBuilds(m_eRouteBuild)) + if(eRouteBuild == NO_BUILD || !kUnitInfo.GetBuilds(eRouteBuild)) return; // no matter if pillaged or not - if(pPlot->getRouteType() == eBestRouteType) - return; - - // the plot was not flagged recently, so ignore - if (!WantRouteAtPlot(pPlot)) + if(pPlot->getRouteType() >= eRoute) return; if(GET_PLAYER(pUnit->getOwner()).isOption(PLAYEROPTION_LEAVE_FORESTS)) @@ -1620,7 +1621,7 @@ void CvBuilderTaskingAI::AddRouteDirectives(vectorgetFeatureType(); if(eFeature != NO_FEATURE) { - CvBuildInfo* pkBuild = GC.getBuildInfo(m_eRouteBuild); + CvBuildInfo* pkBuild = GC.getBuildInfo(eRouteBuild); if(pkBuild && pkBuild->isFeatureRemove(eFeature)) { return; @@ -1631,15 +1632,15 @@ void CvBuilderTaskingAI::AddRouteDirectives(vectorplot(), *pPlot); //tiebreaker in case of multiple equal options BuilderDirective directive; directive.m_eDirective = eDirectiveType; - directive.m_eBuild = m_eRouteBuild; + directive.m_eBuild = eRouteBuild; directive.m_eResource = NO_RESOURCE; directive.m_sX = pPlot->getX(); directive.m_sY = pPlot->getY(); @@ -1985,8 +1986,8 @@ bool CvBuilderTaskingAI::ShouldBuilderConsiderPlot(CvUnit* pUnit, CvPlot* pPlot) return false; } - //can't build in other major player's territory - if (pPlot->isOwned() && pPlot->getOwner()!=pUnit->getOwner() && GET_PLAYER(pPlot->getOwner()).isMajorCiv()) + //can't build in other major player's territory (unless they are our vassal) + if (pPlot->isOwned() && pPlot->getOwner()!=pUnit->getOwner() && GET_PLAYER(pPlot->getOwner()).isMajorCiv() && !GET_TEAM(pPlot->getTeam()).IsVassal(m_pPlayer->getTeam())) return false; // workers should not be able to work in plots that do not match their default domain @@ -2048,7 +2049,7 @@ bool CvBuilderTaskingAI::ShouldBuilderConsiderPlot(CvUnit* pUnit, CvPlot* pPlot) } //danger check is not enough - we don't want to be adjacent to enemy territory for example - if (pPlot->isVisibleToEnemy(pUnit->getOwner())) + if (m_pPlayer->GetTacticalAI()->IsVisibleToEnemy(pPlot)) return false; if (!pUnit->canEndTurnAtPlot(pPlot)) @@ -2748,7 +2749,8 @@ int CvBuilderTaskingAI::ScorePlotBuild(CvUnit* pUnit, CvPlot* pPlot, Improvement } if (iRouteScore > 0) { - if (pPlot->IsCityConnection(m_pPlayer->GetID()) && (pPlot->IsRouteRailroad() || pPlot->IsRouteRoad())) + // If we don't need a route at this plot, it is about to be removed + if (pPlot->IsCityConnection(m_pPlayer->GetID()) && (pPlot->IsRouteRailroad() || pPlot->IsRouteRoad()) && NeedRouteAtPlot(pPlot)) iSecondaryScore += iRouteScore; else iSecondaryScore -= iRouteScore; @@ -2948,17 +2950,16 @@ BuildTypes CvBuilderTaskingAI::GetRemoveRoute(void) return eRemoveRouteBuild; } -BuildTypes CvBuilderTaskingAI::GetBuildRoute(void) +BuildTypes CvBuilderTaskingAI::GetBuildRoute(RouteTypes eRoute) { // find the route build BuildTypes eRouteBuild = NO_BUILD; - RouteTypes eBestRoute = m_pPlayer->getBestRoute(); for(int i = 0; i < GC.getNumBuildInfos(); i++) { BuildTypes eBuild = (BuildTypes)i; CvBuildInfo* pkBuild = GC.getBuildInfo(eBuild); - if(pkBuild && pkBuild->getRoute() == eBestRoute) + if(pkBuild && pkBuild->getRoute() == eRoute) { eRouteBuild = eBuild; break; diff --git a/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.h b/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.h index 68aec96f4d..091190b838 100644 --- a/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.h +++ b/CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.h @@ -106,7 +106,7 @@ class CvBuilderTaskingAI FeatureTypes GetFalloutFeature(void); BuildTypes GetFalloutRemove(void); BuildTypes GetRemoveRoute(void); - BuildTypes GetBuildRoute(void); + BuildTypes GetBuildRoute(RouteTypes eRoute); static void LogInfo(const CvString& str, CvPlayer* pPlayer, bool bWriteToOutput = false); static void LogYieldInfo(const CvString& strNewLogStr, CvPlayer* pPlayer); //Log yield related info to BuilderTaskingYieldLog.csv. @@ -121,8 +121,8 @@ class CvBuilderTaskingAI void LogDirectives(vector> directives, CvUnit* pUnit); void LogDirective(BuilderDirective directive, CvUnit* pUnit, int iWeight, bool bChosen = false); - void ConnectCitiesToCapital(CvCity* pPlayerCapital, CvCity* pTargetCity, BuildTypes eBuild, RouteTypes eRoute, int iNetGoldTimes100); - void ConnectCitiesForShortcuts(CvCity* pFirstCity, CvCity* pSecondCity, BuildTypes eBuild, RouteTypes eRoute, int iNetGoldTimes100); + void ConnectCitiesToCapital(CvCity* pPlayerCapital, CvCity* pTargetCity, BuildTypes eBuild, RouteTypes eRoute); + void ConnectCitiesForShortcuts(CvCity* pFirstCity, CvCity* pSecondCity, BuildTypes eBuild, RouteTypes eRoute); void ConnectCitiesForScenario(CvCity* pFirstCity, CvCity* pSecondCity, BuildTypes eBuild, RouteTypes eRoute); void ConnectPointsForStrategy(CvCity* pOriginCity, CvPlot* pTargetPlot, BuildTypes eBuild, RouteTypes eRoute, int iNetGoldTimes100); @@ -154,7 +154,6 @@ class CvBuilderTaskingAI FeatureTypes m_eFalloutFeature; BuildTypes m_eFalloutRemove; BuildTypes m_eRemoveRouteBuild; - BuildTypes m_eRouteBuild; //some player dependent flags for unique improvements bool m_bKeepMarshes; diff --git a/CvGameCoreDLL_Expansion2/CvDangerPlots.cpp b/CvGameCoreDLL_Expansion2/CvDangerPlots.cpp index c1481f579c..cb70357831 100644 --- a/CvGameCoreDLL_Expansion2/CvDangerPlots.cpp +++ b/CvGameCoreDLL_Expansion2/CvDangerPlots.cpp @@ -812,7 +812,7 @@ int CvDangerPlotContents::GetDanger(const CvUnit* pUnit, const UnitIdContainer& { int iDummy = 0; int iDamage = TacticalAIHelpers::GetSimulatedDamageFromAttackOnUnit(pUnit, pAttacker, m_pPlot, pAttacker->plot(), iDummy, false, 0, true); - if (!m_pPlot->isVisible(pAttacker->getTeam())) + if (!GET_PLAYER(pUnit->getOwner()).GetTacticalAI()->IsVisibleToPlayer(m_pPlot, pAttacker->getTeam())) iDamage = (iDamage * 80) / 100; //there's a chance they won't spot us iPlotDamage += iDamage; } @@ -895,7 +895,7 @@ int CvDangerPlotContents::GetDanger(const CvUnit* pUnit, const UnitIdContainer& //if the attacker is not out of range, assume they need to move for the attack, so we don't know their plot int iDamage = TacticalAIHelpers::GetSimulatedDamageFromAttackOnUnit(pUnit, pAttacker, m_pPlot, bOutOfRange ? pAttacker->plot() : NULL, iAttackerDamage, false, iExtraDamage, true); - if (!m_pPlot->isVisible(pAttacker->getTeam())) + if (!GET_PLAYER(pUnit->getOwner()).GetTacticalAI()->IsVisibleToPlayer(m_pPlot, pAttacker->getTeam())) iDamage = (iDamage * 80) / 100; //there's a chance they won't spot us if (iAttackerDamage >= pAttacker->GetCurrHitPoints() && !pAttacker->isSuicide()) diff --git a/CvGameCoreDLL_Expansion2/CvPlayerAI.cpp b/CvGameCoreDLL_Expansion2/CvPlayerAI.cpp index 0892edf4fb..8d080cd491 100644 --- a/CvGameCoreDLL_Expansion2/CvPlayerAI.cpp +++ b/CvGameCoreDLL_Expansion2/CvPlayerAI.cpp @@ -287,6 +287,7 @@ void CvPlayerAI::AI_unitUpdate() // just been handed off to the tactical AI to get a move in the same turn they switch between GetTacticalAI()->Update(); GetHomelandAI()->Update(); + GetTacticalAI()->CleanUp(); } } diff --git a/CvGameCoreDLL_Expansion2/CvPlot.cpp b/CvGameCoreDLL_Expansion2/CvPlot.cpp index 25b06433b0..d0e9daf708 100644 --- a/CvGameCoreDLL_Expansion2/CvPlot.cpp +++ b/CvGameCoreDLL_Expansion2/CvPlot.cpp @@ -204,6 +204,7 @@ void CvPlot::reset() m_eResourceType = NO_RESOURCE; m_eImprovementType = NO_IMPROVEMENT; m_ePlayerBuiltImprovement = NO_PLAYER; + m_ePlayerBuiltRoute = NO_PLAYER; m_ePlayerResponsibleForImprovement = NO_PLAYER; m_ePlayerResponsibleForRoute = NO_PLAYER; m_ePlayerThatClearedBarbCampHere = NO_PLAYER; @@ -3433,19 +3434,27 @@ bool CvPlot::isAdjacentPlayer(PlayerTypes ePlayer, bool bLandOnly) const } // -------------------------------------------------------------------------------- -bool CvPlot::IsAdjacentOwnedByTeamOtherThan(TeamTypes eTeam, bool bAllowNoTeam, bool bIgnoreImpassable) const +bool CvPlot::IsAdjacentOwnedByTeamOtherThan(TeamTypes eTeam, bool bAllowNoTeam, bool bIgnoreImpassable, bool bIgnoreMinor, bool bIgnoreVassal) const { CvPlot** aPlotsToCheck = GC.getMap().getNeighborsUnchecked(this); for(int iI=0; iIgetTeam() != eTeam) - { - if (bIgnoreImpassable && pAdjacentPlot->isImpassable(pAdjacentPlot->getTeam())) - continue; + if(pAdjacentPlot == NULL) + continue; + + if (bIgnoreImpassable && pAdjacentPlot->isImpassable(pAdjacentPlot->getTeam())) + continue; + + if (bIgnoreMinor && GET_PLAYER(pAdjacentPlot->getOwner()).isMinorCiv()) + continue; - if (bAllowNoTeam || pAdjacentPlot->getTeam() != NO_TEAM) - return true; + if (bIgnoreVassal && GET_TEAM(pAdjacentPlot->getTeam()).IsVassal(eTeam)) + continue; + + if (pAdjacentPlot->getTeam() != eTeam && (pAdjacentPlot->getTeam() != NO_TEAM || bAllowNoTeam)) + { + return true; } } @@ -3535,6 +3544,28 @@ bool CvPlot::IsAdjacentOwnedByEnemy(TeamTypes eTeam) const return false; } +// -------------------------------------------------------------------------------- +bool CvPlot::isAdjacentOwnedByVassal(TeamTypes eTeam, bool bLandOnly) const +{ + CvPlot** aPlotsToCheck = GC.getMap().getNeighborsUnchecked(this); + for (int iI=0; iIgetTeam() != NO_TEAM && GET_TEAM(pAdjacentPlot->getTeam()).IsVassal(eTeam)) + { + if(!bLandOnly || !(pAdjacentPlot->isWater())) + { + return true; + } + } + } + } + + return false; +} + // -------------------------------------------------------------------------------- bool CvPlot::isAdjacentTeam(TeamTypes eTeam, bool bLandOnly) const { @@ -4085,26 +4116,6 @@ bool CvPlot::isVisibleToAnyTeam(bool bNoMinor) const return false; } -// -------------------------------------------------------------------------------- -bool CvPlot::isVisibleToEnemy(PlayerTypes eFriendlyPlayer) const -{ - const std::vector& vEnemies = GET_PLAYER(eFriendlyPlayer).GetPlayersAtWarWith(); - - for (std::vector::const_iterator it = vEnemies.begin(); it != vEnemies.end(); ++it) - { - CvPlayer& kEnemy = GET_PLAYER(*it); - if (kEnemy.isAlive() && kEnemy.IsAtWarWith(eFriendlyPlayer)) - { - if (isVisible(kEnemy.getTeam())) - { - return true; - } - } - } - - return false; -} - // -------------------------------------------------------------------------------- bool CvPlot::isVisibleToWatchingHuman() const @@ -7352,6 +7363,7 @@ void CvPlot::setIsCity(bool bValue, int iCityID, int iWorkRange) { // Maintenance change! SetPlayerResponsibleForRoute(getOwner()); + SetPlayerThatBuiltRoute(getOwner()); } // plot ownership will be changed in CvCity::preKill @@ -8701,6 +8713,9 @@ void CvPlot::setRouteType(RouteTypes eNewValue, PlayerTypes eBuilder) SetPlayerResponsibleForRoute(NO_PLAYER); } + if(eOldRoute != eNewValue) + SetPlayerThatBuiltRoute(eBuilder); + // Route switch here! m_eRouteType = eNewValue; @@ -8825,6 +8840,20 @@ void CvPlot::SetPlayerThatBuiltImprovement(PlayerTypes eBuilder) m_ePlayerBuiltImprovement = eBuilder; } +// -------------------------------------------------------------------------------- +/// Who built this Road? Could be NO_PLAYER +PlayerTypes CvPlot::GetPlayerThatBuiltRoute() const +{ + return (PlayerTypes)m_ePlayerBuiltRoute; +} + +// -------------------------------------------------------------------------------- +/// Who built this Improvement? Could be NO_PLAYER +void CvPlot::SetPlayerThatBuiltRoute(PlayerTypes eBuilder) +{ + m_ePlayerBuiltRoute= eBuilder; +} + // -------------------------------------------------------------------------------- /// Who pays maintenance for this Improvement? PlayerTypes CvPlot::GetPlayerResponsibleForImprovement() const @@ -11293,6 +11322,15 @@ bool CvPlot::setRevealed(TeamTypes eTeam, bool bNewValue, CvUnit* pUnit, bool bT bool bVisbilityUpdated = false; bool bRevealed = isRevealed(eTeam) != bNewValue; + + // Update tactical AI, let it know that the tile was made visible + const CivsList pPlayers = GET_TEAM(eTeam).getPlayers(); + for (size_t iJ = 0; iJ < pPlayers.size(); iJ++) + { + if (pPlayers[iJ] == GC.getGame().getActivePlayer()) + GET_PLAYER(pPlayers[iJ]).GetTacticalAI()->NewVisiblePlot(this, bRevealed); + } + if(bRevealed) { bVisbilityUpdated = true; @@ -12852,6 +12890,7 @@ void CvPlot::Serialize(Plot& plot, Visitor& visitor) visitor(plot.m_ePlayerBuiltImprovement); visitor(plot.m_ePlayerResponsibleForImprovement); + visitor(plot.m_ePlayerBuiltRoute); visitor(plot.m_ePlayerResponsibleForRoute); visitor(plot.m_ePlayerThatClearedBarbCampHere); visitor(plot.m_ePlayerThatClearedDigHere); diff --git a/CvGameCoreDLL_Expansion2/CvPlot.h b/CvGameCoreDLL_Expansion2/CvPlot.h index 23d58cb6b6..f4ddb86930 100644 --- a/CvGameCoreDLL_Expansion2/CvPlot.h +++ b/CvGameCoreDLL_Expansion2/CvPlot.h @@ -208,9 +208,10 @@ class CvPlot bool isAdjacentOwned() const; bool isAdjacentPlayer(PlayerTypes ePlayer, bool bLandOnly = false) const; - bool IsAdjacentOwnedByTeamOtherThan(TeamTypes eTeam, bool bAllowNoTeam=false, bool bIgnoreImpassable=false) const; + bool IsAdjacentOwnedByTeamOtherThan(TeamTypes eTeam, bool bAllowNoTeam=false, bool bIgnoreImpassable=false, bool bIgnoreMinor=false, bool bIgnoreVassal=false) const; bool IsAdjacentOwnedByUnfriendly(PlayerTypes ePlayer, vector& vUnfriendlyMajors) const; bool IsAdjacentOwnedByEnemy(TeamTypes eTeam) const; + bool isAdjacentOwnedByVassal(TeamTypes eTeam, bool bLandOnly = false) const; bool isAdjacentTeam(TeamTypes eTeam, bool bLandOnly = false) const; bool IsAdjacentCity(TeamTypes eTeam = NO_TEAM) const; CvCity* GetAdjacentFriendlyCity(TeamTypes eTeam, bool bLandOnly = false) const; @@ -243,7 +244,6 @@ class CvPlot bool isActiveVisible() const; bool isVisibleToAnyTeam(bool bNoMinor = false) const; - bool isVisibleToEnemy(PlayerTypes eFriendlyPlayer) const; bool isVisibleToWatchingHuman() const; bool isAdjacentVisible(TeamTypes eTeam, bool bDebug=false) const; bool isAdjacentNonvisible(TeamTypes eTeam) const; @@ -502,6 +502,9 @@ class CvPlot // Who built the improvement in this plot? PlayerTypes GetPlayerThatBuiltImprovement() const; void SetPlayerThatBuiltImprovement(PlayerTypes eBuilder); + + PlayerTypes GetPlayerThatBuiltRoute() const; + void SetPlayerThatBuiltRoute(PlayerTypes eBuilder); // Someone footing the bill for an improvement/route in an unowned plot? PlayerTypes GetPlayerResponsibleForImprovement() const; @@ -970,6 +973,7 @@ class CvPlot char /*ResourceTypes*/ m_eResourceType; char /*ImprovementTypes*/ m_eImprovementType; char /*PlayerTypes*/ m_ePlayerBuiltImprovement; + char /*PlayerTypes*/ m_ePlayerBuiltRoute; char /*PlayerTypes*/ m_ePlayerResponsibleForImprovement; char /*PlayerTypes*/ m_ePlayerResponsibleForRoute; char /*PlayerTypes*/ m_ePlayerThatClearedBarbCampHere; diff --git a/CvGameCoreDLL_Expansion2/CvTacticalAI.cpp b/CvGameCoreDLL_Expansion2/CvTacticalAI.cpp index e166db4a45..849fdb8d26 100644 --- a/CvGameCoreDLL_Expansion2/CvTacticalAI.cpp +++ b/CvGameCoreDLL_Expansion2/CvTacticalAI.cpp @@ -314,6 +314,7 @@ void CvTacticalAI::RecruitUnits() /// Update the AI for units void CvTacticalAI::Update() { + UpdateVisibility(); DropOldFocusAreas(); FindTacticalTargets(); @@ -324,6 +325,14 @@ void CvTacticalAI::Update() ProcessDominanceZones(); } +/// Clear up memory usage +void CvTacticalAI::CleanUp() +{ + m_plotsVisibleToOtherPlayer.clear(); + m_AllTargets.clear(); + m_ZoneTargets.clear(); +} + /// Add a temporary focus of attention around a short-term target void CvTacticalAI::AddFocusArea(CvPlot* pPlot, int iRadius, int iDuration) { @@ -373,17 +382,143 @@ bool CvTacticalAI::IsInFocusArea(const CvPlot* pPlot) const return false; } +/// Setup knowledge of other players' seen plots +void CvTacticalAI::UpdateVisibility() +{ + TeamTypes eTeam = m_pPlayer->getTeam(); + + CvPlot* pLoopPlot; + + for (int iI = 0; iI < GC.getMap().numPlots(); iI++) + { + pLoopPlot = GC.getMap().plotByIndexUnchecked(iI); + + if (!pLoopPlot->isRevealed(eTeam)) + continue; + + UpdateVisibilityFromBorders(pLoopPlot, false); + + if (!pLoopPlot->isVisible(eTeam)) + continue; + + NewVisiblePlot(pLoopPlot, false); + } +} + +/// Check if there are any units owned by other players in this tile and what they can see +void CvTacticalAI::NewVisiblePlot(CvPlot* pPlot, bool bRevealed=false) +{ + if (!pPlot) + return; + + TeamTypes eTeam = m_pPlayer->getTeam(); + + // If we just revealed the tile, check if it or a nearby plot is owned by another player + if (bRevealed) + { + UpdateVisibilityFromBorders(pPlot, bRevealed); + } + + if (pPlot->getNumUnits() > 0) + { + TeamTypes eOtherTeam; + CvUnit* pLoopUnit; + + for (int iI = 0; iI < pPlot->getNumUnits(); iI++) + { + pLoopUnit = pPlot->getUnitByIndex(iI); + eOtherTeam = pLoopUnit->getTeam(); + if (eOtherTeam != eTeam && !pLoopUnit->isInvisible(eTeam, false)) + { + for (int iRange = 2; iRange <= pLoopUnit->visibilityRange(); iRange++) + { + const vector& vPlots = GC.getMap().GetPlotsAtRangeX(pPlot, iRange, true, true); + + for (size_t iJ = 0; iJ < vPlots.size(); iJ++) + { + if ((vPlots[iJ]) == NULL) + continue; + + m_plotsVisibleToOtherPlayer[eOtherTeam].insert(vPlots[iJ]->GetPlotIndex()); + } + } + } + } + } +} + +/// Do we know that the other civ can see this tile? +bool CvTacticalAI::IsVisibleToPlayer(const CvPlot* pPlot, TeamTypes eOther) +{ + return m_plotsVisibleToOtherPlayer.count(eOther) > 0 && m_plotsVisibleToOtherPlayer[eOther].count(pPlot->GetPlotIndex()) > 0; +} + +/// Do we know that an enemy civ can see this tile? +bool CvTacticalAI::IsVisibleToEnemy(const CvPlot* pPlot) +{ + const std::vector& vEnemies = m_pPlayer->GetPlayersAtWarWith(); + + for (std::vector::const_iterator it = vEnemies.begin(); it != vEnemies.end(); ++it) + { + CvPlayer& kEnemy = GET_PLAYER(*it); + if (kEnemy.isAlive() && kEnemy.IsAtWarWith(m_pPlayer->GetID())) + { + if (IsVisibleToPlayer(pPlot, kEnemy.getTeam())) + { + return true; + } + } + } + + return false; +} + // PRIVATE METHODS +void CvTacticalAI::UpdateVisibilityFromBorders(CvPlot* pPlot, bool bRevealed) +{ + TeamTypes eTeam = m_pPlayer->getTeam(); + TeamTypes eOtherTeam = pPlot->getTeam(); + CvPlot** aPlotsToCheck = GC.getMap().getNeighborsUnchecked(pPlot); + CvPlot* pAdjacentPlot; + + if (eOtherTeam != NO_TEAM && eOtherTeam != eTeam) + { + // Plot is owned by another player + m_plotsVisibleToOtherPlayer[eOtherTeam].insert(pPlot->GetPlotIndex()); + + if (bRevealed) + { + for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) + { + pAdjacentPlot = aPlotsToCheck[iI]; + + if (pAdjacentPlot != NULL && pAdjacentPlot->isVisible(eTeam)) + // We knew about this plot before but we may not previously have known that this player was neighboring it + m_plotsVisibleToOtherPlayer[eOtherTeam].insert(pAdjacentPlot->GetPlotIndex()); + } + } + } + + for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) + { + pAdjacentPlot = aPlotsToCheck[iI]; + + if (pAdjacentPlot != NULL && pAdjacentPlot->isVisible(eTeam)) { + eOtherTeam = pAdjacentPlot->getTeam(); + + if (eOtherTeam != eTeam && pAdjacentPlot->getTeam() != NO_TEAM) + // Neighbors a plot owned by another player + m_plotsVisibleToOtherPlayer[eOtherTeam].insert(pAdjacentPlot->GetPlotIndex()); + } + } +} + /// Make lists of everything we might want to target with the tactical AI this turn void CvTacticalAI::FindTacticalTargets() { CvPlayerTrade* pPlayerTrade = m_pPlayer->GetTrade(); - // Clear out target list since we rebuild it each turn - m_AllTargets.clear(); - m_ZoneTargets.clear(); - bool bNoBarbsAllowedYet = GC.getGame().getGameTurn() < GC.getGame().GetBarbarianReleaseTurn(); vector vUnfriendlyMajors = m_pPlayer->GetUnfriendlyMajors(); @@ -1205,7 +1340,7 @@ void CvTacticalAI::PlotMovesToSafety(bool bCombatUnits) { // try to flee or hide int iDangerLevel = pUnit->GetDanger(); - if(iDangerLevel > 0 || pUnit->plot()->isVisibleToEnemy(pUnit->getOwner())) + if(iDangerLevel > 0 || IsVisibleToEnemy(pUnit->plot())) { bool bAddUnit = false; if(bCombatUnits) @@ -6396,8 +6531,7 @@ CvPlot* TacticalAIHelpers::FindSafestPlotInReach(const CvUnit* pUnit, bool bAllo iScore += 12; //try to hide - if there are few enemy units, this might be a tiebreaker - //this is cheating a bit, really we need to check if the plot is visible for the enemy units visible to us - if (!pPlot->isVisibleToEnemy(pUnit->getOwner())) + if (!GET_PLAYER(pUnit->getOwner()).GetTacticalAI()->IsVisibleToEnemy(pPlot)) iScore -= iScore / 4; //try to go avoid borders @@ -7668,7 +7802,7 @@ int ScoreTurnEnd(const CvUnit* pUnit, eUnitAssignmentType eLastAssignment, const if (testPlot.hasAirCover()) iResult+=3; //when in doubt, hide from the enemy - if (!testPlot.isVisibleToEnemy()) + if (!GET_PLAYER(pUnit->getOwner()).GetTacticalAI()->IsVisibleToEnemy(testPlot.getPlot())) iResult++; //try to occupy enemy citadels! @@ -8194,7 +8328,7 @@ CvTacticalPlot::CvTacticalPlot(const CvPlot* plot, PlayerTypes ePlayer, const ve //constant bfBlockedByNonSimCombatUnit = 0; bHasAirCover = pPlot->HasAirCover(ePlayer); - bIsVisibleToEnemy = pPlot->isVisibleToEnemy(ePlayer); + bIsVisibleToEnemy = kPlayer.GetTacticalAI()->IsVisibleToEnemy(pPlot); //updated if necessary bEdgeOfTheKnownWorldUnknown = true; diff --git a/CvGameCoreDLL_Expansion2/CvTacticalAI.h b/CvGameCoreDLL_Expansion2/CvTacticalAI.h index babdb4c0ec..658feca752 100644 --- a/CvGameCoreDLL_Expansion2/CvTacticalAI.h +++ b/CvGameCoreDLL_Expansion2/CvTacticalAI.h @@ -333,6 +333,7 @@ class CvTacticalAI // Public turn update routines void Update(); + void CleanUp(); // temporary focus of attention void AddFocusArea(CvPlot* pPlot, int iRadius, int iDuration); @@ -340,6 +341,12 @@ class CvTacticalAI void DropOldFocusAreas(); bool IsInFocusArea(const CvPlot* pPlot) const; + // Knowledge of other civs' vision + void UpdateVisibility(); + void NewVisiblePlot(CvPlot* pPlot, bool bRevealed); + bool IsVisibleToPlayer(const CvPlot* pPlot, TeamTypes eOther); + bool IsVisibleToEnemy(const CvPlot* pPlot); + // For air units bool ShouldRebase(CvUnit* pUnit) const; @@ -466,6 +473,7 @@ class CvTacticalAI bool FindEmbarkedUnitsAroundTarget(CvPlot *pTargetPlot, int iMaxDistance); bool FindCitiesWithinStrikingDistance(CvPlot* pTargetPlot); CvPlot* FindAirTargetNearTarget(CvUnit* pUnit, CvPlot* pTargetPlot); + void UpdateVisibilityFromBorders(CvPlot* pPlot, bool bRevealed); int GetRecruitRange() const; @@ -512,6 +520,9 @@ class CvTacticalAI int m_iCurrentTargetIndex; int m_iCurrentUnitTargetIndex; + // Visibility info + std::map> m_plotsVisibleToOtherPlayer; + std::vector m_focusAreas; };