[Vote] (7-78) Standardize City Tile Yields

Include in VP?


  • Total voters
    75
  • This poll will close: .

Rekk

Deity
Joined
Dec 9, 2017
Messages
2,607
Counterproposal to:

Current Algorithm:
Yields on the city center tile when settling are calculated as follows, in this order:
  1. Start with the base yields from the tile, including any increase from resources on the tile.
  2. If :c5food: Food is less than 2, it is set to 2.
  3. If :c5production: Production is less than 1, it is set to 1.
  4. Add +1 :c5food: Food to cities on flatlands or mountains that have access to fresh water.
  5. Add +1 :c5gold: Gold to cities on flatlands or mountains that have no access to fresh water.
  6. Add +1 :c5production: Production to cities on mountains that have no access to fresh water.
Proposed Algorithm:
  1. Natural Yields on tile are set to 2 :c5food: Food and 1 :c5production: Production.
  2. Add +1 :c5production: Production to cities on hills.
  3. Add +1 :c5food: Food to cities on flatlands or mountains that have access to fresh water.
  4. Add +1 :c5gold: Gold to cities on flatlands or mountains that have no access to fresh water.
  5. Add +1 :c5production: Production to cities on mountains that have no access to fresh water.
  6. Add yields from resources.
Rationale:
We don't have tiles that naturally give 3 food, but we do have tiles that naturally give 2 production (hills). The current algorithm is a very round-about way of setting cities to 2:c5food:1:c5production: + benefits, so we should just make it explicit. The main change seen is that settling on a resource gives its full set of yields (instead of just the yields that exceed the 2:c5food:1:c5production: baseline). In addition, Snow hills will perform like other hills, just like Snow flatland currently performs like other flatlands.

Note:
settling a city destroys the feature on that tile (including Forests, Marshes, and Flood Plains).

Moderator Action: Removed step 7 you added to the current algorithm. Resource yields are included in step 1. So this is actually a more substantial buff than you might think. - Recursive

Edit: Updated rationale and formatting.
 
Last edited:
By the way, how does settling a city interact with flood plains? In my head it removes/ignores the feature, is that correct? (seems from what you wrote but want to check)
 
Destroys them.
 
Moderator Action: Removed step 7 you added to the current algorithm. Resource yields are included in step 1. So this is actually a more substantial buff than you might think. - Recursive
@Recursive Let's talk about this. From what I understand, as an example, if you settle on Grasslands Stone, you don't currently get the benefit from the production that Stone gives?
 
@Recursive Let's talk about this. From what I understand, as an example, if you settle on Grasslands Stone, you don't currently get the benefit from the production that Stone gives?
If a resource grants unimproved yields, those are added to the base yields of the tile. The base yields are then set to max(2, Food) and max(1, Production), plus those special bonuses after.

If a resource grants extra yields when improved, those wouldn't be added.

That's what I saw in the code, anyway.
Code:
int CvPlot::calculateNatureYield(YieldTypes eYield, PlayerTypes ePlayer, FeatureTypes eFeature, ResourceTypes eResource, const CvCity* pOwningCity, bool bDisplay) const
{
    int iYield = 0;
    TeamTypes eTeam = (ePlayer!=NO_PLAYER) ? GET_PLAYER(ePlayer).getTeam() : NO_TEAM;

    //performance critical ...
    static const ImprovementTypes eFort = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_FORT");
    static const ImprovementTypes eCitadel = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_CITADEL");

    const CvYieldInfo& kYield = *GC.getYieldInfo(eYield);
    CvAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");

    // impassable terrain has no base yield (but do allow coast)
    // if worked by a city, it should have a yield.
    if( (!isValidMovePlot(ePlayer) && getOwner()!=ePlayer && (!isShallowWater()) || getTerrainType()==NO_TERRAIN))
    {
        iYield = 0;
    } 
    else
    {
        iYield = GC.getTerrainInfo(getTerrainType())->getYield(eYield);
        if (eYield == YIELD_PRODUCTION && /*0*/ GD_INT_GET(BALANCE_CORE_PRODUCTION_DESERT_IMPROVEMENT) > 0 && getTerrainType() == TERRAIN_DESERT && !isHills() && eFeature == NO_FEATURE)
        {
            if (eResource != NO_RESOURCE && getImprovementType() != NO_IMPROVEMENT)
                iYield += GD_INT_GET(BALANCE_CORE_PRODUCTION_DESERT_IMPROVEMENT);
        }
    }

    iYield += GC.getPlotInfo(getPlotType())->getYield(eYield);
    iYield += GC.getGame().getPlotExtraYield(m_iX, m_iY, eYield);

    if(isHills())
    {
        iYield += kYield.getHillsChange();
    }

    if(isMountain())
    {
        iYield += kYield.getMountainChange();
    }

    if(isLake())
    {
        iYield += kYield.getLakeChange();
    }
    if(eFeature != NO_FEATURE)
    {
        CvFeatureInfo* pFeatureInfo = GC.getFeatureInfo(eFeature);

        // Some Features REPLACE the Yield of the Plot instead of adding to it
        int iYieldChange = pFeatureInfo->getYieldChange(eYield);

        if(pFeatureInfo->isYieldNotAdditive())
        {
            iYield = iYieldChange;
        }
        else
        {
            iYield += iYieldChange;
        }
    }

    if(eTeam != NO_TEAM)
    {
        CvResourceInfo* pkResourceInfo = GC.getResourceInfo(eResource);

        if(eResource != NO_RESOURCE && pkResourceInfo)
        {
            iYield += pkResourceInfo->getYieldChange(eYield);
        }
    }

    if(isRiver())
    {
        iYield += eFeature == NO_FEATURE ? GC.getTerrainInfo(getTerrainType())->getRiverYieldChange(eYield) : GC.getFeatureInfo(eFeature)->getRiverYieldChange(eYield);
    }

    if(isHills())
    {
        iYield += eFeature == NO_FEATURE ? GC.getTerrainInfo(getTerrainType())->getHillsYieldChange(eYield) : GC.getFeatureInfo(eFeature)->getHillsYieldChange(eYield);
    }

    if(isFreshWater())
    {
        iYield += eFeature == NO_FEATURE ? GC.getTerrainInfo(getTerrainType())->getFreshWaterYieldChange(eYield) : GC.getFeatureInfo(eFeature)->getFreshWaterYieldChange(eYield);
    }

    if(isCoastalLand())
    {
        iYield += eFeature == NO_FEATURE ? GC.getTerrainInfo(getTerrainType())->getCoastalLandYieldChange(eYield) : GC.getFeatureInfo(eFeature)->getCoastalLandYieldChange(eYield);
    }

#if defined(MOD_PLOTS_EXTENSIONS)
    if (MOD_PLOTS_EXTENSIONS)
    {
        PlotTypes ePlot = getPlotType();
        if (ePlot != NO_PLOT && GC.getPlotInfo(ePlot)->IsAdjacentFeatureYieldChange())
        {
            // yield from adjacent features
            bool bNaturalWonderPlot = IsNaturalWonder();
            for (int iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
            {
                CvPlot* pAdjacentPlot = plotDirection(getX(), getY(), ((DirectionTypes)iI));

                if (pAdjacentPlot == NULL)
                    continue;

                if (pAdjacentPlot->getFeatureType() != NO_FEATURE)
                {
                    iYield += GC.getPlotInfo(ePlot)->GetAdjacentFeatureYieldChange(pAdjacentPlot->getFeatureType(), eYield, bNaturalWonderPlot);
                }
            }
        }
    }
#endif

    if (pOwningCity != NULL && pOwningCity->plot() == this && ePlayer != NO_PLAYER)
    {
        iYield = std::max(iYield, kYield.getMinCity());

        if (!bDisplay || pOwningCity->isRevealed(GC.getGame().getActiveTeam(), false, false))
        {
            iYield += kYield.getCityChange();

            if (kYield.getPopulationChangeDivisor() != 0)
            {
                iYield += (pOwningCity->getPopulation() + kYield.getPopulationChangeOffset()) / kYield.getPopulationChangeDivisor();
            }
        }

        // GetYieldFromXMilitaryUnits (France UA)
        iYield += GET_PLAYER(ePlayer).GetYieldFromMilitaryUnits(eYield);

        // Mod for Player; used for Policies and such
        iYield += GET_PLAYER(ePlayer).GetPlayerTraits()->GetCityYieldChanges(eYield);

        // Coastal City Mod
        if (pOwningCity->isCoastal())
        {
            iYield += GET_PLAYER(ePlayer).GetCoastalCityYieldChange(eYield);

            iYield += GET_PLAYER(ePlayer).GetPlayerTraits()->GetCoastalCityYieldChanges(eYield);

        }

        if (MOD_BALANCE_YIELD_SCALE_ERA)
        {
            //Flatland City Fresh Water yields
            if (!isHills() && !isMountain() && isFreshWater())
            {
                iYield += kYield.getMinCityFlatFreshWater();
            }
            //Flatland City No Fresh Water yields
            if (!isHills() && !isMountain() && !isFreshWater())
            {
                iYield += kYield.getMinCityFlatNoFreshWater();
            }
            // Hill City Fresh Water yields
            if (isHills() && isFreshWater())
            {
                iYield += kYield.getMinCityHillFreshWater();
            }
            // Hill City No Fresh Water yields
            if (isHills() && !isFreshWater())
            {
                iYield += kYield.getMinCityHillNoFreshWater();
            }
            // Mountain City Fresh Water yields
            if (isMountain() && isFreshWater())
            {
                iYield += kYield.getMinCityMountainFreshWater();
            }
            // Mountain City No Fresh Water yields
            if (isMountain() && !isFreshWater())
            {
                iYield += kYield.getMinCityMountainNoFreshWater();
            }
            if (pOwningCity->HasGarrison())
            {
                CvUnit* pUnit = pOwningCity->GetGarrisonedUnit();
                if (pUnit != NULL && pUnit->GetGarrisonYieldChange(eYield) > 0)
                {
                    int iGarrisonStrength = pUnit->GetBaseCombatStrength();
                    iYield += ((pUnit->GetGarrisonYieldChange(eYield) * iGarrisonStrength) / 8);
                }
            }
            if (pOwningCity->plot()->getImprovementType() == eFort || pOwningCity->plot()->getImprovementType() == eCitadel)
            {
            // Don't provide yield if tile is pillaged
                if (!pOwningCity->plot()->IsImprovementPillaged())
                {
                    // If there are any Units here, meet their owners
                    for (int iUnitLoop = 0; iUnitLoop < getNumUnits(); iUnitLoop++)
                    {
                        // If the AI spots a human Unit, don't meet - wait for the human to find the AI
                        CvUnit* loopUnit = getUnitByIndex(iUnitLoop);
                        if (!loopUnit)
                            continue;
    
                        if (loopUnit->GetFortificationYieldChange(eYield) > 0)
                        {
                            int iUnitStrength = loopUnit->GetBaseCombatStrength();
                            iYield += ((loopUnit->GetFortificationYieldChange(eYield) * iUnitStrength) / 8);
                        }
                    }
                }
            }
        }

        int iTemp = GET_PLAYER(ePlayer).GetCityYieldChangeTimes100(eYield);    // In hundreds - will be added to capitalYieldChange below

                                                                                // Capital Mod
        if (pOwningCity->isCapital())
        {
            iTemp += GET_PLAYER(ePlayer).GetCapitalYieldChangeTimes100(eYield);

            iYield += GET_PLAYER(ePlayer).GetPlayerTraits()->GetCapitalYieldChanges(eYield);

            int iPerPopYield = pOwningCity->getPopulation() * GET_PLAYER(getOwner()).GetCapitalYieldPerPopChange(eYield);
            iPerPopYield /= 100;
            iYield += iPerPopYield;

            if (GET_PLAYER(ePlayer).GetCapitalYieldPerPopChangeEmpire(eYield) != 0)
            {
                int iPerPopYieldEmpire = GET_PLAYER(ePlayer).getTotalPopulation() * GET_PLAYER(ePlayer).GetCapitalYieldPerPopChangeEmpire(eYield);
                //Implied 100x, see ChangeCapitalYieldPerPopChangeEmpire.
                iPerPopYieldEmpire /= 100;
                iYield += iPerPopYieldEmpire;
            }
        }

        iYield += (iTemp / 100);
    }

    return std::max(0, iYield);
}
 
From what I understand, as an example, if you settle on Grasslands Stone, you don't currently get the benefit from the production that Stone gives?
yes. also if you settle on a desert horse, no production from it. or if you settle on a flood plains wheat (4 food), the tile's food drops to 3! because you destroy the flood plains
 
Why, though? When you settle on diamonds then you get diamonds, so they are not destroyed.
 
features are destroyed. gems is a resource, not a feature.

the wheat in my example is not destroyed. it just doesn't help your yields. (though I think you get the +1 from granary)
 
I sponsor this.
 
Top Bottom