void CvCityAI::AI_doHurry(bool bForce)
{
PROFILE_FUNC();
CvArea* pWaterArea;
UnitTypes eProductionUnit;
UnitAITypes eProductionUnitAI;
BuildingTypes eProductionBuilding;
int iHurryAngerLength;
int iHurryPopulation;
int iMinTurns;
bool bDanger;
bool bWait;
bool bEssential;
bool bGrowth;
int iI, iJ;
FAssert(!isHuman() || isProductionAutomated());
if (isBarbarian())
{
return;
}
if ((getProduction() == 0) && !bForce)
{
return;
}
pWaterArea = waterArea();
eProductionUnit = getProductionUnit();
eProductionUnitAI = getProductionUnitAI();
eProductionBuilding = getProductionBuilding();
bDanger = AI_isDanger();
for (iI = 0; iI < GC.getNumHurryInfos(); iI++)
{
if (canHurry((HurryTypes)iI))
{
if (bForce)
{
hurry((HurryTypes)iI);
break;
}
iHurryAngerLength = hurryAngerLength((HurryTypes)iI);
iHurryPopulation = hurryPopulation((HurryTypes)iI);
iMinTurns = MAX_INT;
bEssential = false;
bGrowth = false;
// Whip to eliminate unhappiness - thank you Blake!
if (getProduction() > 0)
{
if (AI_getHappyFromHurry((HurryTypes)iI) > 0)
{
hurry((HurryTypes)iI);
break;
}
}
if ((iHurryAngerLength == 0) && (iHurryPopulation == 0))
{
if (GET_PLAYER(getOwnerINLINE()).AI_avoidScience())
{
if (GET_PLAYER(getOwnerINLINE()).getGold() > GET_PLAYER(getOwnerINLINE()).AI_goldTarget())
{
iMinTurns = std::min(iMinTurns, 10);
}
}
if (eProductionBuilding != NO_BUILDING)
{
int iValuePerTurn = AI_buildingValueThreshold(eProductionBuilding, BUILDINGFOCUS_GOLD | BUILDINGFOCUS_MAINTENANCE | BUILDINGFOCUS_PRODUCTION);
iValuePerTurn /= 3;
if (iValuePerTurn > 0)
{
int iHurryGold = hurryGold((HurryTypes)iI);
if ((iHurryGold / iValuePerTurn) < getProductionTurnsLeft(eProductionBuilding, 1))
{
if (iHurryGold < (GET_PLAYER(getOwnerINLINE()).getGold() / 3))
{
hurry((HurryTypes)iI);
return;
}
}
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (isWorldWonderClass((BuildingClassTypes)(GC.getBuildingInfo(eProductionBuilding).getBuildingClassType())))
{
iMinTurns = std::min(iMinTurns, 10);
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getDefenseModifier() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getBombardDefenseModifier() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getYieldModifier(YIELD_PRODUCTION) > 0)
{
if (getBaseYieldRate(YIELD_PRODUCTION) >= 6)
{
iMinTurns = std::min(iMinTurns, 10);
bGrowth = true;
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if ((GC.getBuildingInfo(eProductionBuilding).getCommerceChange(COMMERCE_CULTURE) > 0) ||
(GC.getBuildingInfo(eProductionBuilding).getObsoleteSafeCommerceChange(COMMERCE_CULTURE) > 0))
{
if ((getCommerceRateTimes100(COMMERCE_CULTURE) == 0) || (plot()->calculateCulturePercent(getOwnerINLINE()) < 40))
{
iMinTurns = std::min(iMinTurns, 10);
if (getCommerceRateTimes100(COMMERCE_CULTURE) == 0)
{
bEssential = true;
iMinTurns = std::min(iMinTurns, 5);
if (AI_countNumBonuses(NO_BONUS, false, true, 2, true, true) > 0)
{
bGrowth = true;
}
}
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getHappiness() > 0)
{
if (angryPopulation() > 0)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getHealth() > 0)
{
if (healthRate() < 0)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getSeaPlotYieldChange(YIELD_FOOD) > 0 || GC.getBuildingInfo(eProductionBuilding).getRiverPlotYieldChange(YIELD_FOOD) > 0)
{
iMinTurns = std::min(iMinTurns, 10);
if (AI_buildingSpecialYieldChangeValue(eProductionBuilding, YIELD_FOOD) > (getPopulation() * 2))
{
bEssential = true;
bGrowth = true;
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getFreeExperience() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getMaintenanceModifier() < 0)
{
if (getMaintenance() >= 10)
{
iMinTurns = std::min(iMinTurns, 10);
bEssential = true;
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getDefineINT("DEFAULT_SPECIALIST") != NO_SPECIALIST)
{
if (getSpecialistCount((SpecialistTypes)(GC.getDefineINT("DEFAULT_SPECIALIST"))) > 0)
{
for (iJ = 0; iJ < GC.getNumSpecialistInfos(); iJ++)
{
if (GC.getBuildingInfo(eProductionBuilding).getSpecialistCount(iJ) > 0)
{
iMinTurns = std::min(iMinTurns, 10);
break;
}
}
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getCommerceModifier(COMMERCE_GOLD) > 0)
{
if (GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble())
{
if (getBaseCommerceRate(COMMERCE_GOLD) >= 16)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getCommerceModifier(COMMERCE_RESEARCH) > 0)
{
if (!(GET_PLAYER(getOwnerINLINE()).AI_avoidScience()))
{
if (getBaseCommerceRate(COMMERCE_RESEARCH) >= 16)
{
iMinTurns = std::min(iMinTurns, 10);
}
}
}
}
if (eProductionBuilding != NO_BUILDING)
{
if (GC.getBuildingInfo(eProductionBuilding).getFoodKept() > 0)
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}
if (eProductionUnit != NO_UNIT)
{
if (GC.getUnitInfo(eProductionUnit).getDomainType() == DOMAIN_LAND)
{
if (GC.getUnitInfo(eProductionUnit).getCombat() > 0)
{
if (bDanger)
{
iMinTurns = std::min(iMinTurns, 3);
bEssential = true;
}
}
}
}
if (eProductionUnitAI == UNITAI_CITY_DEFENSE)
{
if (plot()->plotCheck(PUF_isUnitAIType, UNITAI_SETTLE, -1, getOwnerINLINE()) != NULL)
{
if (!AI_isDefended(-2)) // XXX check for other team's units?
{
iMinTurns = std::min(iMinTurns, 5);
}
}
}
if (eProductionUnitAI == UNITAI_SETTLE)
{
if (area()->getNumAIUnits(getOwnerINLINE(), UNITAI_SETTLE) == 0)
{
if (!(GET_PLAYER(getOwnerINLINE()).AI_isFinancialTrouble()))
{
if (area()->getBestFoundValue(getOwnerINLINE()) > 0)
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}
}
}
if (eProductionUnitAI == UNITAI_SETTLER_SEA)
{
if (pWaterArea != NULL)
{
if (pWaterArea->getNumAIUnits(getOwnerINLINE(), UNITAI_SETTLER_SEA) == 0)
{
if (area()->getNumAIUnits(getOwnerINLINE(), UNITAI_SETTLE) > 0)
{
iMinTurns = std::min(iMinTurns, 5);
}
}
}
}
if (eProductionUnitAI == UNITAI_WORKER)
{
if (GET_PLAYER(getOwnerINLINE()).AI_neededWorkers(area()) > (area()->getNumAIUnits(getOwnerINLINE(), UNITAI_WORKER) * 2))
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}
if (eProductionUnitAI == UNITAI_WORKER_SEA)
{
if (AI_neededSeaWorkers() > 0)
{
iMinTurns = std::min(iMinTurns, 5);
bEssential = true;
bGrowth = true;
}
}
// adjust for game speed
if (NO_UNIT != getProductionUnit())
{
iMinTurns *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
}
else if (NO_BUILDING != getProductionBuilding())
{
iMinTurns *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent();
}
else if (NO_PROJECT != getProductionProject())
{
iMinTurns *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getCreatePercent();
}
else
{
iMinTurns *= 100;
}
iMinTurns /= 100;
//this overrides everything.
if (bGrowth)
{
int iHurryGold = hurryGold((HurryTypes)iI);
if ((iHurryGold > 0) && ((iHurryGold * 16) < GET_PLAYER(getOwnerINLINE()).getGold()))
{
hurry((HurryTypes)iI);
break;
}
if (AI_countGoodTiles((healthRate(0) == 0), false, 100) <= (getPopulation() - iHurryPopulation))
{
hurry((HurryTypes)iI);
break;
}
}
if (AI_countGoodTiles((healthRate(0) == 0), false, 100) <= (getPopulation() - iHurryPopulation))
{
if (getProductionTurnsLeft() > iMinTurns)
{
bWait = isHuman();
if ((iHurryPopulation * 3) > (getProductionTurnsLeft() * 2))
{
bWait = true;
}
if (!bWait)
{
if (iHurryAngerLength > 0)
{
//is the whip just too small or the population just too reduced to bother?
if (!bEssential && ((iHurryPopulation < (1 + GC.getDefineINT("HURRY_POP_ANGER"))) || ((getPopulation() - iHurryPopulation) <= std::max(3, (getHighestPopulation() / 2)))))
{
bWait = true;
}
else
{
//sometimes it's worth whipping even with existing anger
if (getHurryAngerTimer() > 1)
{
if (!bEssential)
{
bWait = true;
}
else if (GC.getDefineINT("HURRY_POP_ANGER") == iHurryPopulation && angryPopulation() > 0)
{
//ideally we'll whip something more expensive
bWait = true;
}
}
}
//if the city is just lame then don't whip the poor thing
//(it'll still get whipped when unhappy/unhealthy)
if (!bWait && !bEssential)
{
int iFoodSurplus = 0;
CvPlot * pLoopPlot;
for (iJ = 0; iJ < NUM_CITY_PLOTS; iJ++)
{
if (iJ != CITY_HOME_PLOT)
{
pLoopPlot = getCityIndexPlot(iJ);
if (pLoopPlot != NULL)
{
if (pLoopPlot->getWorkingCity() == this)
{
iFoodSurplus += std::max(0, pLoopPlot->getYield(YIELD_FOOD) - GC.getFOOD_CONSUMPTION_PER_POPULATION());
}
}
}
}
if (iFoodSurplus < 3)
{
bWait = true;
}
}
}
}
if (!bWait)
{
hurry((HurryTypes)iI);
break;
}
}
}
}
}
}