Skip to content

Commit

Permalink
Buildings.NoStarvationNonSpecialist
Browse files Browse the repository at this point in the history
  • Loading branch information
axatin authored and RecursiveVision committed Dec 4, 2024
1 parent 346de1a commit 63b47c4
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 7 deletions.
9 changes: 8 additions & 1 deletion CvGameCoreDLL_Expansion2/CvBuildingClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ CvBuildingEntry::CvBuildingEntry(void):
m_iGrantsRandomResourceTerritory(0),
m_bPuppetPurchaseOverride(false),
m_bAllowsPuppetPurchase(false),
m_bNoStarvationNonSpecialist(false),
m_iGetCooldown(0),
m_bTradeRouteInvulnerable(false),
m_iTRSpeedBoost(0),
Expand Down Expand Up @@ -926,6 +927,7 @@ bool CvBuildingEntry::CacheResults(Database::Results& kResults, CvDatabaseUtilit
m_iGrantsRandomResourceTerritory = kResults.GetInt("GrantsRandomResourceTerritory");
m_bPuppetPurchaseOverride = kResults.GetBool("PuppetPurchaseOverride");
m_bAllowsPuppetPurchase = kResults.GetBool("AllowsPuppetPurchase");
m_bNoStarvationNonSpecialist = kResults.GetBool("NoStarvationNonSpecialist");
m_iGetCooldown = kResults.GetInt("PurchaseCooldown");
m_iNumPoliciesNeeded = kResults.GetInt("NumPoliciesNeeded");
#endif
Expand Down Expand Up @@ -1832,11 +1834,16 @@ bool CvBuildingEntry::IsPuppetPurchaseOverride() const
{
return m_bPuppetPurchaseOverride;
}
/// Dpes this building unlock purchasing in any city?
/// Does this building unlock purchasing in any city?
bool CvBuildingEntry::IsAllowsPuppetPurchase() const
{
return m_bAllowsPuppetPurchase;
}
/// Does this building prevent non-specialists to consume more food than the city's food production?
bool CvBuildingEntry::IsNoStarvationNonSpecialist() const
{
return m_bNoStarvationNonSpecialist;
}
/// Does this building have a cooldown cost when purchased?
int CvBuildingEntry::GetCooldown() const
{
Expand Down
2 changes: 2 additions & 0 deletions CvGameCoreDLL_Expansion2/CvBuildingClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ class CvBuildingEntry: public CvBaseInfo
int GrantsRandomResourceTerritory() const;
bool IsPuppetPurchaseOverride() const;
bool IsAllowsPuppetPurchase() const;
bool IsNoStarvationNonSpecialist() const;
int GetCooldown() const;
bool IsTradeRouteInvulnerable() const;
int GetTRSpeedBoost() const;
Expand Down Expand Up @@ -711,6 +712,7 @@ class CvBuildingEntry: public CvBaseInfo
int m_iGrantsRandomResourceTerritory;
bool m_bPuppetPurchaseOverride;
bool m_bAllowsPuppetPurchase;
bool m_bNoStarvationNonSpecialist;
int m_iGetCooldown;
bool m_bTradeRouteInvulnerable;
int m_iTRSpeedBoost;
Expand Down
27 changes: 25 additions & 2 deletions CvGameCoreDLL_Expansion2/CvCity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ CvCity::CvCity() :
, m_iResourceDiversityModifier()
, m_iNoUnhappfromXSpecialists()
, m_bNoWarmonger()
, m_iNoStarvationNonSpecialist()
#endif
#if defined(MOD_BALANCE_CORE)
, m_abIsBestForWonder()
Expand Down Expand Up @@ -1390,6 +1391,7 @@ void CvCity::reset(int iID, PlayerTypes eOwner, int iX, int iY, bool bConstructo
m_iResourceDiversityModifier = 0;
m_iNoUnhappfromXSpecialists = 0;
m_bNoWarmonger = false;
m_iNoStarvationNonSpecialist = 0;
#endif
m_aiEconomicValue.resize(MAX_CIV_PLAYERS);
for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
Expand Down Expand Up @@ -14227,6 +14229,10 @@ void CvCity::processBuilding(BuildingTypes eBuilding, int iChange, bool bFirst,
{
SetAllowPuppetPurchase(pBuildingInfo->IsAllowsPuppetPurchase() * iChange > 0);
}
if (pBuildingInfo->IsNoStarvationNonSpecialist())
{
ChangeNoStarvationNonSpecialist(iChange);
}

changeGreatPeopleRateModifier(pBuildingInfo->GetGreatPeopleRateModifier() * iChange);
changeGPRateModPerMarriage(pBuildingInfo->GetGPRateModPerMarriage() * iChange);
Expand Down Expand Up @@ -16260,14 +16266,19 @@ int CvCity::foodConsumption(bool bNoAngry, int iExtra) const
return foodConsumptionTimes100(bNoAngry, iExtra * 100) / 100;
}
// --------------------------------------------------------------------------------
int CvCity::foodConsumptionTimes100(bool /*bNoAngry*/, int iExtra) const
int CvCity::foodConsumptionTimes100(bool /*bNoAngry*/, int iExtra, bool bAssumeNoReductionForNonSpecialists) const
{
VALIDATE_OBJECT

int iSpecialists = GetCityCitizens()->GetTotalSpecialistCount();
int iNonSpecialists = max(0, (getPopulation() - iSpecialists)) + iExtra;

return max(100, foodConsumptionNonSpecialistTimes100() * iNonSpecialists + foodConsumptionSpecialistTimes100() * iSpecialists);
int iConsumptionNonSpecialists = foodConsumptionNonSpecialistTimes100() * iNonSpecialists;
if (IsNoStarvationNonSpecialist() && !bAssumeNoReductionForNonSpecialists)
{
iConsumptionNonSpecialists = min(getYieldRateTimes100(YIELD_FOOD, false), iConsumptionNonSpecialists);
}
return max(100, iConsumptionNonSpecialists + foodConsumptionSpecialistTimes100() * iSpecialists);
}


Expand Down Expand Up @@ -22733,6 +22744,17 @@ bool CvCity::IsNoWarmongerYet()
return m_bNoWarmonger;
}

void CvCity::ChangeNoStarvationNonSpecialist(int iValue)
{
VALIDATE_OBJECT
m_iNoStarvationNonSpecialist += iValue;
}
bool CvCity::IsNoStarvationNonSpecialist() const
{
VALIDATE_OBJECT
return m_iNoStarvationNonSpecialist > 0;
}

int CvCity::GetNumTimesOwned(PlayerTypes ePlayer) const
{
VALIDATE_OBJECT
Expand Down Expand Up @@ -31663,6 +31685,7 @@ void CvCity::Serialize(City& city, Visitor& visitor)
visitor(city.m_iLocalUnhappinessMod);
visitor(city.m_bNoWarmonger);
visitor(city.m_iEmpireSizeModifierReduction);
visitor(city.m_iNoStarvationNonSpecialist);
visitor(city.m_iDistressFlatReduction);
visitor(city.m_iPovertyFlatReduction);
visitor(city.m_iIlliteracyFlatReduction);
Expand Down
7 changes: 6 additions & 1 deletion CvGameCoreDLL_Expansion2/CvCity.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ class CvCity
int foodConsumptionNonSpecialistTimes100() const;
int foodConsumptionSpecialistTimes100() const;
int foodConsumption(bool bNoAngry = false, int iExtra = 0) const;
int foodConsumptionTimes100(bool bNoAngry = false, int iExtra = 0) const;
int foodConsumptionTimes100(bool bNoAngry = false, int iExtra = 0, bool bAssumeNoReductionForNonSpecialists = false) const;
int foodDifference(bool bJustCheckingStarve = false) const;
int foodDifferenceTimes100(bool bJustCheckingStarve = false, CvString* toolTipSink = NULL) const;
int growthThreshold() const;
Expand Down Expand Up @@ -1012,6 +1012,9 @@ class CvCity
void SetNoWarmonger(bool bValue);
bool IsNoWarmongerYet();

void ChangeNoStarvationNonSpecialist(int iValue);
bool IsNoStarvationNonSpecialist() const;

int GetNumTimesOwned(PlayerTypes ePlayer) const;
void SetNumTimesOwned(PlayerTypes ePlayer, int iValue);
void ChangeNumTimesOwned(PlayerTypes ePlayer, int iValue);
Expand Down Expand Up @@ -2021,6 +2024,7 @@ class CvCity
int m_iNumNearbyMountains;
int m_iLocalUnhappinessMod;
bool m_bNoWarmonger;
int m_iNoStarvationNonSpecialist;
int m_iEmpireSizeModifierReduction;
int m_iDistressFlatReduction;
int m_iPovertyFlatReduction;
Expand Down Expand Up @@ -2421,6 +2425,7 @@ SYNC_ARCHIVE_VAR(int, m_iDeepWaterTileDamage)
SYNC_ARCHIVE_VAR(int, m_iNumNearbyMountains)
SYNC_ARCHIVE_VAR(int, m_iLocalUnhappinessMod)
SYNC_ARCHIVE_VAR(bool, m_bNoWarmonger)
SYNC_ARCHIVE_VAR(int, m_iNoStarvationNonSpecialist)
SYNC_ARCHIVE_VAR(int, m_iEmpireSizeModifierReduction)
SYNC_ARCHIVE_VAR(int, m_iDistressFlatReduction)
SYNC_ARCHIVE_VAR(int, m_iPovertyFlatReduction)
Expand Down
29 changes: 26 additions & 3 deletions CvGameCoreDLL_Expansion2/CvCityCitizens.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -921,8 +921,8 @@ int CvCityCitizens::GetBaseValuePerYield(YieldTypes eYield, SPrecomputedExpensiv
switch (eYield)
{
case YIELD_FOOD:
// in small cities, treat being under the growth threshold like starvation
if (bAssumeStarving || (bAssumeBelowGrowthThreshold && m_pCity->getPopulation() <= 3))
// in small cities, treat being under the growth threshold like starvation, unless we focus on a yield other than food
if (bAssumeStarving || (bAssumeBelowGrowthThreshold && m_pCity->getPopulation() <= 3 && (eFocus == NO_CITY_AI_FOCUS_TYPE || eFocus == CITY_AI_FOCUS_TYPE_FOOD || eFocus == CITY_AI_FOCUS_TYPE_GOLD_GROWTH || eFocus == CITY_AI_FOCUS_TYPE_PROD_GROWTH)))
iYieldMod = /*500*/ GD_INT_GET(AI_CITIZEN_VALUE_FOOD_STARVING);
else if (bAssumeBelowGrowthThreshold || eFocus == CITY_AI_FOCUS_TYPE_FOOD || (pkProcessInfo && pkProcessInfo->getProductionToYieldModifier(eYield) > 0))
iYieldMod = /*32*/ GD_INT_GET(AI_CITIZEN_VALUE_FOOD_NEED_GROWTH);
Expand Down Expand Up @@ -1085,6 +1085,20 @@ int CvCityCitizens::ScoreYieldChangeQuick(YieldAndGPPList yieldChanges, SPrecomp
YieldTypes eYield = (YieldTypes)iI;
int iYield100 = yieldChanges.yield[iI];

// Inca exception: if we're already under the non-specialist food consumption threshold, we can safely remove even more food ...
if (m_pCity->IsNoStarvationNonSpecialist() && eYield == YIELD_FOOD && iYield100 < 0 && cache.iFoodConsumptionTimes100 <= cache.iFoodConsumptionAssumeNoReductionNonSpecialistsTimes100)
{
// ... unless we're adding a specialist
int iNumSpecialistAdded = 0;
for (int iI = 0; iI < (int)yieldChanges.iNumSpecialists.size(); iI++)
{
iNumSpecialistAdded += yieldChanges.iNumSpecialists[iI];
}
if (iNumSpecialistAdded <= 0)
continue;

}

if (iYield100 != 0)
{
int iYieldMod = GetBaseValuePerYield(eYield, cache, bAssumeStarving, bAssumeBelowGrowthThreshold, bAssumeInDebt);
Expand Down Expand Up @@ -1243,6 +1257,13 @@ int CvCityCitizens::ScoreYieldChange(YieldAndGPPList yieldChanges, SPrecomputedE
int iNetFoodNow = cache.iFoodRateTimes100 - cache.iFoodConsumptionTimes100;
// food consumption also depends on how many specialists are worked
int iNetFoodThen = iNetFoodNow + iYield100 - iNumSpecialistsAdded * (m_pCity->foodConsumptionSpecialistTimes100() - m_pCity->foodConsumptionNonSpecialistTimes100());
if (m_pCity->IsNoStarvationNonSpecialist())
{
// if non-specialists can't cause starvation, the calculation is more complicated. we have to recalculate current and future food consumption by non-specialists manually
// iNetFoodThen = iNetFoodNow + (Change in Food Rate) - (Change in Food Consumption)
// with (Change in Food Consumption) = (Future Food Consumption Non-Specialists) - (Current Food Consumption Non-Specialists) + (Change in Food Consumption Specialists)
iNetFoodThen = iNetFoodNow + iYield100 - (min(cache.iFoodRateTimes100 + iYield100, cache.iFoodConsumptionAssumeNoReductionNonSpecialistsTimes100 - iNumSpecialistsAdded * m_pCity->foodConsumptionNonSpecialistTimes100()) - min(cache.iFoodRateTimes100, cache.iFoodConsumptionAssumeNoReductionNonSpecialistsTimes100) + iNumSpecialistsAdded * m_pCity->foodConsumptionSpecialistTimes100());
}

// special case of building a settler: all excess food is converted into production
if (m_pCity->isFoodProduction())
Expand Down Expand Up @@ -2027,7 +2048,7 @@ void CvCityCitizens::OptimizeWorkedPlots(bool bLogging)
const int iNumOptionsSpecialists = 5;

//failsafe against switching back and forth, don't try this too often
while (iCount < max(1, m_pCity->getPopulation() / 2))
while (iCount < max(5, m_pCity->getPopulation() / 2))
{
//now the real check. unassigning a tile might cause the valuation of the other tiles to change, so we have to consider combinations
int iNetFood100 = m_pCity->getYieldRateTimes100(YIELD_FOOD, false) - m_pCity->foodConsumptionTimes100();
Expand Down Expand Up @@ -3680,6 +3701,7 @@ SPrecomputedExpensiveNumbers::SPrecomputedExpensiveNumbers() :
iOtherUnhappiness(0),
iFoodRateTimes100(0),
iFoodConsumptionTimes100(0),
iFoodConsumptionAssumeNoReductionNonSpecialistsTimes100(0),
iFoodCorpMod(0),
bWantArt(false),
bWantScience(false),
Expand All @@ -3695,6 +3717,7 @@ void SPrecomputedExpensiveNumbers::update(CvCity* pCity, bool bInsideLoop)
iGrowthMod = pCity->getGrowthMods();
iFoodRateTimes100 = pCity->getYieldRateTimes100(YIELD_FOOD, false);
iFoodConsumptionTimes100 = pCity->foodConsumptionTimes100();
iFoodConsumptionAssumeNoReductionNonSpecialistsTimes100 = pCity->foodConsumptionTimes100(false, 0, true);

if (MOD_BALANCE_VP)
{
Expand Down
1 change: 1 addition & 0 deletions CvGameCoreDLL_Expansion2/CvCityCitizens.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ struct SPrecomputedExpensiveNumbers
bool bNeedUpdate;
int iFoodRateTimes100;
int iFoodConsumptionTimes100;
int iFoodConsumptionAssumeNoReductionNonSpecialistsTimes100;
int iFoodCorpMod;
int iFamine;
int iDistress;
Expand Down
9 changes: 9 additions & 0 deletions CvGameCoreDLL_Expansion2/CvCityStrategyAI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5240,6 +5240,15 @@ int CityStrategyAIHelpers::GetBuildingBasicValue(CvCity *pCity, BuildingTypes eB
{
iValue += pkBuildingInfo->GetFoodKept() * pCity->getPopulation();
}
if (pkBuildingInfo->IsNoStarvationNonSpecialist() && !pCity->IsNoStarvationNonSpecialist())
{
iValue += 10 * pCity->getPopulation();
if (pCity->foodDifferenceTimes100(false) < 0)
{
// higher value if we are starving
iValue += (-2) * pCity->foodDifferenceTimes100(false);
}
}

if (pkBuildingInfo->AllowsFoodTradeRoutes())
{
Expand Down

0 comments on commit 63b47c4

Please sign in to comment.