Skip to content

Commit

Permalink
Some small bug fixes/tweaks (#10510)
Browse files Browse the repository at this point in the history
Don't take city connection bonuses into account when planning routes for cities that are already connected.

Fix rare case where Songhai/Iroquois route trait wasn't taken into account in route pathfinding.

Update visibility logic to take into account city states giving vision to allies.

Fix bug causing worker recommendations not to work.
  • Loading branch information
KungCheops authored Dec 22, 2023
1 parent 768fb4d commit a25b7e3
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 44 deletions.
2 changes: 1 addition & 1 deletion (1) Community Patch/Core Files/CoreLua/InGame.lua
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ function OnUpdateSelection( isSelected )
aWorkerSuggestHighlightPlots = player:GetRecommendedWorkerPlots();

-- Player can disable tile recommendations
if (aFounderSuggestHighlightPlots ~= nil and not OptionsManager.IsNoTileRecommendations()) then
if (aWorkerSuggestHighlightPlots ~= nil and not OptionsManager.IsNoTileRecommendations()) then
for i, v in ipairs(aWorkerSuggestHighlightPlots) do
if (v.plot ~= nil) then
local hexID = ToHexFromGrid( Vector2( v.plot:GetX(), v.plot:GetY() ) );
Expand Down
2 changes: 1 addition & 1 deletion CvGameCoreDLL_Expansion2/CvAIOperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1615,7 +1615,7 @@ bool CvAIOperationMilitary::CheckTransitionToNextStage()
int nVisible = 0;
for (CvUnit* pUnit = pThisArmy->GetFirstUnit(); pUnit; pUnit = pThisArmy->GetNextUnit(pUnit))
{
if (GET_PLAYER(pUnit->getOwner()).GetTacticalAI()->IsVisibleToPlayer(pUnit->plot(), GET_PLAYER(m_eEnemy).getTeam()))
if (GET_PLAYER(m_eOwner).GetTacticalAI()->IsVisibleToPlayer(pUnit->plot(), GET_PLAYER(m_eEnemy).getTeam()))
nVisible++;
}

Expand Down
14 changes: 7 additions & 7 deletions CvGameCoreDLL_Expansion2/CvAStar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2298,12 +2298,16 @@ int BuildRouteCost(const CvAStarNode* /*parent*/, const CvAStarNode* node, const
return iCost;
}

static bool IsSafeForRoute(CvPlot* pPlot, CvPlayer* pPlayer)
static bool IsSafeForRoute(CvPlot* pPlot, CvPlayer* pPlayer, RouteTypes eRoute)
{
TeamTypes ePlotTeam = pPlot->getTeam();
TeamTypes ePlayerTeam = pPlayer->getTeam();
PlayerTypes ePlotOwner = pPlot->getOwner();

//Free routes from traits are always safe
if (pPlayer->GetBuilderTaskingAI()->GetSameRouteBenefitFromTrait(pPlot, eRoute))
return TRUE;

// Our plots and surrounding plots are safe
if (ePlotTeam == ePlayerTeam || pPlot->isAdjacentTeam(pPlayer->getTeam(), false))
{
Expand Down Expand Up @@ -2387,15 +2391,11 @@ int BuildRouteValid(const CvAStarNode* parent, const CvAStarNode* node, const SP
}
}

//Free routes from traits are always safe
if (thisPlayer.GetBuilderTaskingAI()->GetSameRouteBenefitFromTrait(pNewPlot, eRoute))
return TRUE;

//if the plot and its parent are both too far from our borders, don't build here
if (!IsSafeForRoute(pNewPlot, &thisPlayer))
if (!IsSafeForRoute(pNewPlot, &thisPlayer, eRoute))
{
CvPlot* pFromPlot = GC.getMap().plotUnchecked(parent->m_iX, parent->m_iY);
if (!IsSafeForRoute(pFromPlot, &thisPlayer))
if (!IsSafeForRoute(pFromPlot, &thisPlayer, eRoute))
return FALSE;
}

Expand Down
86 changes: 51 additions & 35 deletions CvGameCoreDLL_Expansion2/CvBuilderTaskingAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,48 +323,52 @@ void CvBuilderTaskingAI::ConnectCitiesToCapital(CvCity* pPlayerCapital, CvCity*
else
{
int iMaintenancePerTile = pRouteInfo->GetGoldMaintenance()*(100+m_pPlayer->GetImprovementGoldMaintenanceMod());
int iGoldForRoute = m_pPlayer->GetTreasury()->GetCityConnectionRouteGoldTimes100(pTargetCity);
bool bHasCityConnection = m_pPlayer->IsCityConnectedToCity(pPlayerCapital, pTargetCity, eRoute);
int iGoldForRoute = !bHasCityConnection ? m_pPlayer->GetTreasury()->GetCityConnectionRouteGoldTimes100(pTargetCity) : 0;

//route has side benefits also (movement, village gold, trade route range, religion spread)
int iSideBenefits = 500 + iRoadLength * 100;

//assume one unhappiness is worth gold per turn per city
iSideBenefits += pTargetCity->GetUnhappinessFromIsolation() * (m_pPlayer->IsEmpireUnhappy() ? 200 : 100);
iSideBenefits += bHasCityConnection ? pTargetCity->GetUnhappinessFromIsolation() * (m_pPlayer->IsEmpireUnhappy() ? 200 : 100) : 0;

if(GC.getGame().GetIndustrialRoute() == eRoute)
{
iSideBenefits += pTargetCity->getYieldRate(YIELD_PRODUCTION, false) * /*25 in CP, 0 in VP*/ GD_INT_GET(INDUSTRIAL_ROUTE_PRODUCTION_MOD);
if (!bHasCityConnection)
{
iSideBenefits += pTargetCity->getYieldRate(YIELD_PRODUCTION, false) * /*25 in CP, 0 in VP*/ GD_INT_GET(INDUSTRIAL_ROUTE_PRODUCTION_MOD);

#if defined(MOD_BALANCE_CORE)
// Target city would get a production and gold boost from a train station.
for (int iBuildingIndex = 0; iBuildingIndex < GC.getNumBuildingInfos(); iBuildingIndex++)
{
BuildingTypes eBuilding = (BuildingTypes)iBuildingIndex;
CvBuildingEntry* pkBuilding = GC.getBuildingInfo(eBuilding);
if (pkBuilding == NULL)
continue;
// Target city would get a production and gold boost from a train station.
for (int iBuildingIndex = 0; iBuildingIndex < GC.getNumBuildingInfos(); iBuildingIndex++)
{
BuildingTypes eBuilding = (BuildingTypes)iBuildingIndex;
CvBuildingEntry* pkBuilding = GC.getBuildingInfo(eBuilding);
if (pkBuilding == NULL)
continue;

bool bRequiresRail = pkBuilding->IsRequiresRail();
if (!bRequiresRail)
continue;
bool bRequiresRail = pkBuilding->IsRequiresRail();
if (!bRequiresRail)
continue;

int iProductionYield = pTargetCity->getYieldRate(YIELD_PRODUCTION, false);
int iGoldYield = pTargetCity->getYieldRate(YIELD_GOLD, false);
int iProductionYieldRateModifier = pkBuilding->GetYieldModifier(YIELD_PRODUCTION);
int iGoldYieldRateModifier = pkBuilding->GetYieldModifier(YIELD_GOLD);
int iProductionYield = pTargetCity->getYieldRate(YIELD_PRODUCTION, false);
int iGoldYield = pTargetCity->getYieldRate(YIELD_GOLD, false);
int iProductionYieldRateModifier = pkBuilding->GetYieldModifier(YIELD_PRODUCTION);
int iGoldYieldRateModifier = pkBuilding->GetYieldModifier(YIELD_GOLD);

if (pTargetCity->HasBuilding(eBuilding))
{
iSideBenefits += 100 * iProductionYield * iProductionYieldRateModifier / (100 + iProductionYieldRateModifier);
iSideBenefits += 100 * iGoldYield * iGoldYieldRateModifier / (100 + iGoldYieldRateModifier);
}
else if (m_pPlayer->canConstruct(eBuilding) || eBuilding == pTargetCity->getProductionBuilding())
{
iSideBenefits += iProductionYield * iProductionYieldRateModifier;
iSideBenefits += iGoldYield * iGoldYieldRateModifier;
if (pTargetCity->HasBuilding(eBuilding))
{
iSideBenefits += 100 * iProductionYield * iProductionYieldRateModifier / (100 + iProductionYieldRateModifier);
iSideBenefits += 100 * iGoldYield * iGoldYieldRateModifier / (100 + iGoldYieldRateModifier);
}
else if (m_pPlayer->canConstruct(eBuilding) || eBuilding == pTargetCity->getProductionBuilding())
{
iSideBenefits += iProductionYield * iProductionYieldRateModifier;
iSideBenefits += iGoldYield * iGoldYieldRateModifier;
}
}
}
#endif
}

// railroads have extra benefits over normal roads
iSideBenefits += iRoadLength * 150;
Expand Down Expand Up @@ -2739,21 +2743,33 @@ int CvBuilderTaskingAI::ScorePlotBuild(CvUnit* pUnit, CvPlot* pPlot, Improvement
}

//Let's get route things on routes, and not elsewhere.
int iRouteScore = 0;
int iRailroadScore = 0;
int iRoadScore = 0;
for(int iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
YieldTypes eYield = (YieldTypes) iI;

iRouteScore += pImprovement->GetRouteYieldChanges(ROUTE_RAILROAD, eYield) * 100;
iRouteScore += pImprovement->GetRouteYieldChanges(ROUTE_ROAD, eYield) * 100;
iRailroadScore += pImprovement->GetRouteYieldChanges(ROUTE_RAILROAD, eYield) * 100;
iRoadScore += pImprovement->GetRouteYieldChanges(ROUTE_ROAD, eYield) * 100;
}
if (iRouteScore > 0)
if (iRailroadScore > 0 || iRoadScore > 0)
{
// 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;
if (pPlot->IsCityConnection(m_pPlayer->GetID()))
{
bool bHaveAndNeedRailroad = pPlot->IsRouteRailroad() && GetRouteTypeNeededAtPlot(pPlot) == ROUTE_RAILROAD;
bool bHaveAndNeedRoad = pPlot->IsRouteRoad() && GetRouteTypeNeededAtPlot(pPlot) == ROUTE_ROAD && !GetSameRouteBenefitFromTrait(pPlot, ROUTE_ROAD) == ROUTE_ROAD;

if (bHaveAndNeedRailroad)
iSecondaryScore += iRailroadScore;
else if (bHaveAndNeedRoad)
iSecondaryScore += iRoadScore;
else
iSecondaryScore -= max(iRailroadScore, iRoadScore);
}
else
iSecondaryScore -= iRouteScore;
{
iSecondaryScore -= max(iRailroadScore, iRoadScore);
}
}

//City adjacenct improvement? Ramp it up - other stuff can move somewhere else
Expand Down
21 changes: 21 additions & 0 deletions CvGameCoreDLL_Expansion2/CvTacticalAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,13 +423,20 @@ void CvTacticalAI::NewVisiblePlot(CvPlot* pPlot, bool bRevealed=false)
{
TeamTypes eOtherTeam;
CvUnit* pLoopUnit;
PlayerTypes eOtherPlayer;
PlayerTypes eMinorCivAlly = NO_PLAYER;

for (int iI = 0; iI < pPlot->getNumUnits(); iI++)
{
pLoopUnit = pPlot->getUnitByIndex(iI);
eOtherTeam = pLoopUnit->getTeam();
eOtherPlayer = pLoopUnit->getOwner();
if (eOtherTeam != eTeam && !pLoopUnit->isInvisible(eTeam, false))
{
if (GET_TEAM(eOtherTeam).isMinorCiv())
{
eMinorCivAlly = GET_PLAYER(eOtherPlayer).GetMinorCivAI()->GetAlly();
}
for (int iRange = 2; iRange <= pLoopUnit->visibilityRange(); iRange++)
{
const vector<CvPlot*>& vPlots = GC.getMap().GetPlotsAtRangeX(pPlot, iRange, true, true);
Expand All @@ -440,6 +447,8 @@ void CvTacticalAI::NewVisiblePlot(CvPlot* pPlot, bool bRevealed=false)
continue;

m_plotsVisibleToOtherPlayer[eOtherTeam].insert(vPlots[iJ]->GetPlotIndex());
if (eMinorCivAlly != NO_PLAYER)
m_plotsVisibleToOtherPlayer[GET_PLAYER(eMinorCivAlly).getTeam()].insert(vPlots[iJ]->GetPlotIndex());
}
}
}
Expand Down Expand Up @@ -479,13 +488,21 @@ void CvTacticalAI::UpdateVisibilityFromBorders(CvPlot* pPlot, bool bRevealed)
{
TeamTypes eTeam = m_pPlayer->getTeam();
TeamTypes eOtherTeam = pPlot->getTeam();
PlayerTypes eOtherPlayer = pPlot->getOwner();
PlayerTypes eMinorCivAlly = NO_PLAYER;
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 (GET_TEAM(eOtherTeam).isMinorCiv())
{
eMinorCivAlly = GET_PLAYER(eOtherPlayer).GetMinorCivAI()->GetAlly();
if (eMinorCivAlly != NO_PLAYER)
m_plotsVisibleToOtherPlayer[GET_PLAYER(eMinorCivAlly).getTeam()].insert(pPlot->GetPlotIndex());
}

if (bRevealed)
{
Expand All @@ -494,8 +511,12 @@ void CvTacticalAI::UpdateVisibilityFromBorders(CvPlot* pPlot, bool bRevealed)
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());
if (eMinorCivAlly != NO_PLAYER)
m_plotsVisibleToOtherPlayer[GET_PLAYER(eMinorCivAlly).getTeam()].insert(pAdjacentPlot->GetPlotIndex());
}
}
}
}
Expand Down

0 comments on commit a25b7e3

Please sign in to comment.