devolution
Prince
*First Post Reserved*
bool CvPlot::canTrain(UnitTypes eUnit, bool bContinue, bool bTestVisible) const
{
PROFILE_FUNC();
CvCity* pCity = getPlotCity();
/************************************************************************************************/
/* REVDCM 04/16/10 phungus420 */
/* */
/* CanTrain Performance */
/************************************************************************************************/
CvUnitInfo& kUnit = GC.getUnitInfo(eUnit);
int iI;
if (kUnit.isPrereqReligion())
{
if (NULL == pCity || pCity->getReligionCount() > 0)
{
return false;
}
}
if (kUnit.getPrereqReligion() != NO_RELIGION)
{
if (NULL == pCity || !pCity->isHasReligion((ReligionTypes)(kUnit.getPrereqReligion())))
{
return false;
}
}
if (kUnit.getPrereqCorporation() != NO_CORPORATION)
{
if (NULL == pCity || !pCity->isActiveCorporation((CorporationTypes)(kUnit.getPrereqCorporation())))
{
return false;
}
}
if (kUnit.isPrereqBonuses())
{
if (kUnit.getDomainType() == DOMAIN_SEA)
{
bool bValid = false;
for (iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
{
CvPlot* pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (pLoopPlot->isWater())
{
if (pLoopPlot->area()->getNumTotalBonuses() > 0)
{
bValid = true;
break;
}
}
}
}
if (!bValid)
{
return false;
}
}
else
{
if (area()->getNumTotalBonuses() > 0)
{
return false;
}
}
}
if (isCity())
{
if (kUnit.getDomainType() == DOMAIN_SEA)
{
if (!isWater() && !isCoastalLand(kUnit.getMinAreaSize()))
{
return false;
}
}
else
{
if (area()->getNumTiles() < kUnit.getMinAreaSize())
{
return false;
}
}
}
else
{
if (area()->getNumTiles() < kUnit.getMinAreaSize())
{
return false;
}
if (kUnit.getDomainType() == DOMAIN_SEA)
{
if (!isWater())
{
return false;
}
}
else if (kUnit.getDomainType() == DOMAIN_LAND)
{
if (isWater())
{
return false;
}
}
else
{
return false;
}
}
if (!bTestVisible)
{
if (kUnit.getHolyCity() != NO_RELIGION)
{
if (NULL == pCity || !pCity->isHolyCity(((ReligionTypes)(kUnit.getHolyCity()))))
{
return false;
}
}
if (kUnit.getPrereqAndBonus() != NO_BONUS)
{
if (NULL == pCity)
{
if (!isPlotGroupConnectedBonus(getOwnerINLINE(), (BonusTypes)kUnit.getPrereqAndBonus()))
{
return false;
}
}
else
{
const bool hasBonus = pCity->hasBonus((BonusTypes)kUnit.getPrereqAndBonus());
const BuildingTypes eBuilding = (BuildingTypes)kUnit.getOverrideResourceBuilding();
// Erik: If the city does not have the bonus AND the unit does not have an overrider, bail
if (!hasBonus && eBuilding == NO_BUILDING)
{
return false;
}
// Erik: Check that the city has the overriding building
if (!hasBonus && !(pCity->getNumRealBuilding(eBuilding) > 0))
{
return false;
}
}
}
bool bRequiresBonus = false;
bool bNeedsBonus = true;
const BuildingTypes eBuilding = (BuildingTypes)kUnit.getOverrideResourceBuilding();
if (eBuilding != NO_BUILDING)
{
if (pCity->getNumRealBuilding(eBuilding) > 0)
{
// Erik: If we have the overriding building we don't have to check for resources being
// available
return true;
}
}
for (iI = 0; iI < GC.getNUM_UNIT_PREREQ_OR_BONUSES(); ++iI)
{
if (kUnit.getPrereqOrBonuses(iI) != NO_BONUS)
{
bRequiresBonus = true;
if (NULL == pCity)
{
if (isPlotGroupConnectedBonus(getOwnerINLINE(), (BonusTypes)kUnit.getPrereqOrBonuses(iI)))
{
bNeedsBonus = false;
break;
}
}
else
{
if (pCity->hasBonus((BonusTypes)kUnit.getPrereqOrBonuses(iI)))
/************************************************************************************************/
/* REVDCM END Performance */
/************************************************************************************************/
{
bNeedsBonus = false;
break;
}
}
}
}
if (bRequiresBonus && bNeedsBonus)
{
return false;
}
}
return true;
}
// Movement Limits by 45deg - START
bool CvUnit::isInsideMovementLimits (const CvPlot* pPlot) const
{
CvCity* pBestCity;
int iLoop;
pBestCity = GET_PLAYER(getOwnerINLINE()).getCapitalCity();
int iBestDistance = MAX_INT;
for (CvCity* pLoopCity = GET_PLAYER(getOwnerINLINE()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(getOwnerINLINE()).nextCity(&iLoop))
{
int iDistance = plotDistance(getX_INLINE(), getY_INLINE(), pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE());
if (iDistance < iBestDistance)
{
pBestCity = pLoopCity;
iBestDistance = iDistance;
}
}
int iBaseRadius = GC.getDefineINT("BASE_EXPLORATION_RADIUS");
int iRadius = 0;
int iRadiusScaled = 0;
iRadiusScaled = iBaseRadius + GC.getMapINLINE().getWorldSize();
iRadius += iRadiusScaled;
for (int iI = 0; iI < GC.getNumTechInfos(); iI++)
{
if (GC.getTechInfo((TechTypes)iI).isExtendMovementLimits())
{
if (GET_TEAM(getTeam()).isHasTech((TechTypes)iI))
{
iRadius += iRadiusScaled;
}
}
}
for (int iJ = 0; iJ < GC.getNumTechInfos(); iJ++)
{
if (GC.getTechInfo((TechTypes)iJ).isRemoveMovementLimits())
{
if (GET_TEAM(getTeam()).isHasTech((TechTypes)iJ))
{
iRadius = -1;
}
}
}
if (isBarbarian() || GET_PLAYER(getOwnerINLINE()).getNumCities() < 1)
{
iRadius = -1;
}
if (iRadius != -1)
{
if (pPlot != NULL)
{
if ((getTeam() != NO_TEAM) && (GET_PLAYER(pPlot->getOwnerINLINE()).getTeam() != NO_TEAM) && (GET_PLAYER(pPlot->getOwnerINLINE()).getTeam() < 100 /*temporary hack for pitboss*/) && !isBarbarian() && (!GET_PLAYER(pPlot->getOwnerINLINE()).isBarbarian()) && (!gDLL->IsPitbossHost()))
{
int jDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pBestCity->getX_INLINE(), pBestCity->getY_INLINE());
if ((!GET_TEAM(GET_PLAYER(getOwnerINLINE()).getTeam()).isOpenBorders((GET_PLAYER(pPlot->getOwnerINLINE()).getTeam()))) && /*(!GET_TEAM(pPlot->getTeam()).isVassal(getTeam())) && */(!atWar(getTeam(), (GET_PLAYER(pPlot->getOwnerINLINE()).getTeam()))) && !(isRivalTerritory()) && (!pPlot->isRoute()) && (pPlot->getOwnerINLINE() != getOwnerINLINE()) && (jDistance > iRadius+1))
{
return false;
}
}
}
}
return true;
}
void CvGameTextMgr::setRouteHelp(CvWStringBuffer &szBuffer, RouteTypes eRoute, bool bCivilopediaText)
{
CvWString szTempBuffer;
CvWString szFirstBuffer;
int iI;
if (NO_ROUTE == eRoute)
{
return;
}
CvRouteInfo& info = GC.getRouteInfo(eRoute);
if (!bCivilopediaText)
{
szTempBuffer.Format( SETCOLR L"%s" ENDCOLR, TEXT_COLOR("COLOR_HIGHLIGHT_TEXT"), info.getDescription());
szBuffer.append(szTempBuffer);
setYieldChangeHelp(szBuffer, L", ", L"", L"", info.getYieldChangeArray(), false, false);
for (int iTech = 0; iTech < GC.getNumTechInfos(); iTech++)
{
if (GC.getGameINLINE().canEverResearch((TechTypes)iTech))
{
if (0 != info.getTechMovementChange(iTech))
{
szBuffer.append(NEWLINE);
szBuffer.append(gDLL->getText("TXT_KEY_MOVEMENT_ROUTE_WITH_TECH", info.getTechMovementChange(iTech), gDLL->getSymbolID(MOVES_CHAR), GC.getTechInfo((TechTypes)iTech).getTextKeyWide()));
}
}
}
}
if (info.isSeaTunnel())
{
szBuffer.append(NEWLINE);
szBuffer.append(gDLL->getText("TXT_KEY_ROUTE_SEA_TUNNEL"));
}
if (info.getMovementCost() != 0)
{
szBuffer.append(NEWLINE);
szBuffer.append(gDLL->getText("TXT_KEY_ROUTE_MOVEMENT_COST", info.getMovementCost()));
}
if (info.getFlatMovementCost() != 0)
{
szBuffer.append(NEWLINE);
szBuffer.append(gDLL->getText("TXT_KEY_ROUTE_FLAT_MOVEMENT_COST", info.getFlatMovementCost()));
}
if (info.getPrereqBonus() != NO_BONUS)
{
if ((GC.getGame().getActivePlayer()!= NO_PLAYER && !GET_PLAYER(GC.getGame().getActivePlayer()).hasBonus((BonusTypes)info.getPrereqBonus())) || GC.getGame().getActivePlayer() == NO_PLAYER)
{
if (info.isAnyPrereqOrBonus())
{
bool bQualified = true;
if ((GC.getGame().getActivePlayer()!= NO_PLAYER && !GET_PLAYER(GC.getGame().getActivePlayer()).hasBonus((BonusTypes)info.getPrereqBonus())) || GC.getGame().getActivePlayer() == NO_PLAYER)
{
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
BonusTypes eBonusOrPrereq = (BonusTypes)iI;
if (eBonusOrPrereq != NO_BONUS)
{
if (GET_PLAYER(GC.getGame().getActivePlayer()).hasBonus((BonusTypes)info.getPrereqOrBonus(eBonusOrPrereq)))
{
bQualified = false;
}
}
}
if (bQualified)
{
szBuffer.append(NEWLINE);
szBuffer.append(gDLL->getText("TXT_KEY_ROUTE_REQUIRES_BONUS", GC.getBonusInfo((BonusTypes)info.getPrereqBonus()).getTextKeyWide()));
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
BonusTypes eBonusOrPrereq = (BonusTypes)iI;
if (eBonusOrPrereq != NO_BONUS)
{
if ((GC.getGame().getActivePlayer() != NO_PLAYER && !GET_PLAYER(GC.getGame().getActivePlayer()).hasBonus((BonusTypes)info.getPrereqOrBonus(eBonusOrPrereq))) || GC.getGame().getActivePlayer() != NO_PLAYER)
{
szBuffer.append(gDLL->getText("TXT_KEY_ROUTE_REQUIRES_BONUS_OR", GC.getBonusInfo((BonusTypes)info.getPrereqOrBonus(eBonusOrPrereq)).getTextKeyWide()));
}
}
}
}
}
}
else
{
szBuffer.append(NEWLINE);
szBuffer.append(gDLL->getText("TXT_KEY_ROUTE_REQUIRES_BONUS", GC.getBonusInfo((BonusTypes)info.getPrereqBonus()).getTextKeyWide()));
}
}
}
info.getPropertyManipulators()->buildDisplayString(szBuffer);
}
void CvGameTextMgr::setGoodHealthHelp(CvWStringBuffer &szBuffer, CvCity& city)
{
CvPlot* pLoopPlot;
FeatureTypes eFeature;
int iHealth;
int iI;
if (city.goodHealth() > 0)
{
iHealth = city.getFreshWaterGoodHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_HEALTH_FROM_FRESH_WATER", iHealth));
szBuffer.append(NEWLINE);
}
iHealth = city.getFeatureGoodHealth();
if (iHealth > 0)
{
eFeature = NO_FEATURE;
for (iI = 0; iI < NUM_CITY_PLOTS; ++iI)
{
pLoopPlot = plotCity(city.getX_INLINE(), city.getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
if (pLoopPlot->getFeatureType() != NO_FEATURE)
{
if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).getHealthPercent() > 0)
{
if (eFeature == NO_FEATURE)
{
eFeature = pLoopPlot->getFeatureType();
}
else if (eFeature != pLoopPlot->getFeatureType())
{
eFeature = NO_FEATURE;
break;
}
}
}
}
}
szBuffer.append(gDLL->getText("TXT_KEY_MISC_FEAT_GOOD_HEALTH", iHealth, ((eFeature == NO_FEATURE) ? L"TXT_KEY_MISC_FEATURES" : GC.getFeatureInfo(eFeature).getTextKeyWide())));
szBuffer.append(NEWLINE);
}
/************************************************************************************************/
/* JOOYO_ADDON, Added by Jooyo, 06/19/09 */
/* */
/* */
/************************************************************************************************/
iHealth = city.getImprovementGoodHealth() / 100;
CvPlayer &kPlayer = GET_PLAYER(city.getOwnerINLINE());
if (iHealth > 0)
{
int iTotalHealth = 0;
for (int iI = 0; iI < GC.getNumImprovementInfos(); iI++)
{
int iImprovementHealth = 0;
if (GC.getImprovementInfo((ImprovementTypes)iI).getHealthPercent() > 0)
{
const int iNumCityPlots = city.getNumCityPlots();
for (int iJ = 0; iJ < city.getNumCityPlots(); ++iJ)
{
pLoopPlot = plotCity(city.getX_INLINE(), city.getY_INLINE(), iJ);
if (pLoopPlot != NULL)
{
if (pLoopPlot->getImprovementType() == iI)
{
iImprovementHealth += GC.getImprovementInfo((ImprovementTypes)iI).getHealthPercent();
for (int iK = 0; iK < GC.getNumCivicOptionInfos(); iK++)
{
if (kPlayer.getCivics((CivicOptionTypes)iK) != NO_CIVIC)
{
iImprovementHealth += std::max(0, GC.getCivicInfo(kPlayer.getCivics((CivicOptionTypes)iK)).getImprovementHealthPercentChanges(iI)) / 100;
}
}
}
}
}
}
iImprovementHealth /= 100;
if (iImprovementHealth != 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_IMPR_GOOD_HEALTH", iImprovementHealth, GC.getImprovementInfo((ImprovementTypes)iI).getTextKeyWide()));
szBuffer.append(NEWLINE);
iTotalHealth += iImprovementHealth;
}
}
//Show remainder as generic improvement unhealthy
if (iTotalHealth < iHealth)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_IMPR_GOOD_HEALTH", (iHealth - iTotalHealth), L"TXT_KEY_MISC_IMPROVEMENTS"));
szBuffer.append(NEWLINE);
}
}
/************************************************************************************************/
/* JOOYO_ADDON END */
/************************************************************************************************/
/************************************************************************************************/
/* Specialists Enhancements, by Supercheese 10/9/09 */
/* */
/* */
/************************************************************************************************/
iHealth = city.getSpecialistGoodHealth() / 100;
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_GOOD_HEALTH_FROM_SPECIALISTS", iHealth));
szBuffer.append(NEWLINE);
}
/************************************************************************************************/
/* Specialists Enhancements END */
/************************************************************************************************/
iHealth = city.getPowerGoodHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_POWER", iHealth));
szBuffer.append(NEWLINE);
}
iHealth = city.getBonusGoodHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_BONUSES", iHealth));
szBuffer.append(NEWLINE);
}
iHealth = city.totalGoodBuildingHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_BUILDINGS", iHealth));
szBuffer.append(NEWLINE);
}
// Erik: Check that the city actually has a religion
ReligionTypes eReligion = GET_PLAYER(city.getOwnerINLINE()).getStateReligion();
if (eReligion != NO_RELIGION && city.isHasReligion(eReligion))
{
iHealth = GET_PLAYER(city.getOwnerINLINE()).getStateReligionHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_HEALTH_STATE_RELIGION", iHealth));
szBuffer.append(NEWLINE);
}
}
/************************************************************************************************/
/* Afforess Start 01/29/10 */
/* */
/* Traits Were displaying Civic Health too */
/************************************************************************************************/
iHealth = GET_PLAYER(city.getOwnerINLINE()).getCivicHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_CIVICS", iHealth));
szBuffer.append(NEWLINE);
}
iHealth = GET_PLAYER(city.getOwnerINLINE()).getCivilizationHealth();
/************************************************************************************************/
/* Afforess END */
/************************************************************************************************/
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_CIV", iHealth));
szBuffer.append(NEWLINE);
}
// Koshling - event health
iHealth = GET_PLAYER(city.getOwnerINLINE()).getExtraHealth() - GET_PLAYER(city.getOwnerINLINE()).getCivicHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_EVENTS", iHealth));
szBuffer.append(NEWLINE);
}
iHealth = city.getExtraHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_HEALTH_EXTRA", iHealth));
szBuffer.append(NEWLINE);
}
if ( GC.getGame().getHandicapType() != NO_HANDICAP )
{
iHealth = GC.getHandicapInfo(city.getHandicapType()).getHealthBonus();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_HANDICAP", iHealth));
szBuffer.append(NEWLINE);
}
}
/************************************************************************************************/
/* Afforess Start 01/03/10 */
/* */
/* */
/************************************************************************************************/
iHealth = (GET_PLAYER(city.getOwnerINLINE()).getWorldHealth());
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_WORLD_PROJECT", iHealth));
szBuffer.append(NEWLINE);
}
iHealth = (GET_PLAYER(city.getOwnerINLINE()).getProjectHealth());
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_PROJECT", iHealth));
szBuffer.append(NEWLINE);
}
iHealth = city.calculateCorporationHealth();
if (iHealth > 0)
{
szBuffer.append(gDLL->getText("TXT_KEY_MISC_GOOD_HEALTH_FROM_CORPORATION", iHealth));
szBuffer.append(NEWLINE);
}
/************************************************************************************************/
/* Afforess END */
/************************************************************************************************/
szBuffer.append(L"-----------------------\n");
szBuffer.append(gDLL->getText("TXT_KEY_MISC_TOTAL_HEALTHY", city.goodHealth()));
}
}
This makes OverrideFunctionalBuilding functional
I've noticed that r1084 attempted to fix this issue but then r1085 reverted it. I based this code on r1082 and it worked fine when I tested it close to a year ago. Hopefully it's still correct.
Just replace the existing CvPlot::canTrain with the following:
Code:bool CvPlot::canTrain(UnitTypes eUnit, bool bContinue, bool bTestVisible) const { PROFILE_FUNC(); CvCity* pCity = getPlotCity(); /************************************************************************************************/ /* REVDCM 04/16/10 phungus420 */ /* */ /* CanTrain Performance */ /************************************************************************************************/ CvUnitInfo& kUnit = GC.getUnitInfo(eUnit); int iI; if (kUnit.isPrereqReligion()) { if (NULL == pCity || pCity->getReligionCount() > 0) { return false; } } if (kUnit.getPrereqReligion() != NO_RELIGION) { if (NULL == pCity || !pCity->isHasReligion((ReligionTypes)(kUnit.getPrereqReligion()))) { return false; } } if (kUnit.getPrereqCorporation() != NO_CORPORATION) { if (NULL == pCity || !pCity->isActiveCorporation((CorporationTypes)(kUnit.getPrereqCorporation()))) { return false; } } if (kUnit.isPrereqBonuses()) { if (kUnit.getDomainType() == DOMAIN_SEA) { bool bValid = false; for (iI = 0; iI < NUM_DIRECTION_TYPES; ++iI) { CvPlot* pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if (pLoopPlot->isWater()) { if (pLoopPlot->area()->getNumTotalBonuses() > 0) { bValid = true; break; } } } } if (!bValid) { return false; } } else { if (area()->getNumTotalBonuses() > 0) { return false; } } } if (isCity()) { if (kUnit.getDomainType() == DOMAIN_SEA) { if (!isWater() && !isCoastalLand(kUnit.getMinAreaSize())) { return false; } } else { if (area()->getNumTiles() < kUnit.getMinAreaSize()) { return false; } } } else { if (area()->getNumTiles() < kUnit.getMinAreaSize()) { return false; } if (kUnit.getDomainType() == DOMAIN_SEA) { if (!isWater()) { return false; } } else if (kUnit.getDomainType() == DOMAIN_LAND) { if (isWater()) { return false; } } else { return false; } } if (!bTestVisible) { if (kUnit.getHolyCity() != NO_RELIGION) { if (NULL == pCity || !pCity->isHolyCity(((ReligionTypes)(kUnit.getHolyCity())))) { return false; } } if (kUnit.getPrereqAndBonus() != NO_BONUS) { if (NULL == pCity) { if (!isPlotGroupConnectedBonus(getOwnerINLINE(), (BonusTypes)kUnit.getPrereqAndBonus())) { return false; } } else { const bool hasBonus = pCity->hasBonus((BonusTypes)kUnit.getPrereqAndBonus()); const BuildingTypes eBuilding = (BuildingTypes)kUnit.getOverrideResourceBuilding(); // Erik: If the city does not have the bonus AND the unit does not have an overrider, bail if (!hasBonus && eBuilding == NO_BUILDING) { return false; } // Erik: Check that the city has the overriding building if (!hasBonus && !(pCity->getNumRealBuilding(eBuilding) > 0)) { return false; } } } bool bRequiresBonus = false; bool bNeedsBonus = true; const BuildingTypes eBuilding = (BuildingTypes)kUnit.getOverrideResourceBuilding(); if (eBuilding != NO_BUILDING) { if (pCity->getNumRealBuilding(eBuilding) > 0) { // Erik: If we have the overriding building we don't have to check for resources being // available return true; } } for (iI = 0; iI < GC.getNUM_UNIT_PREREQ_OR_BONUSES(); ++iI) { if (kUnit.getPrereqOrBonuses(iI) != NO_BONUS) { bRequiresBonus = true; if (NULL == pCity) { if (isPlotGroupConnectedBonus(getOwnerINLINE(), (BonusTypes)kUnit.getPrereqOrBonuses(iI))) { bNeedsBonus = false; break; } } else { if (pCity->hasBonus((BonusTypes)kUnit.getPrereqOrBonuses(iI))) /************************************************************************************************/ /* REVDCM END Performance */ /************************************************************************************************/ { bNeedsBonus = false; break; } } } } if (bRequiresBonus && bNeedsBonus) { return false; } } return true; }
bool CvPlot::canTrain(UnitTypes eUnit, bool bContinue, bool bTestVisible) const
{
PROFILE_FUNC();
CvCity* pCity = getPlotCity();
/************************************************************************************************/
/* REVDCM 04/16/10 phungus420 */
/* */
/* CanTrain Performance */
/************************************************************************************************/
CvUnitInfo& kUnit = GC.getUnitInfo(eUnit);
int iI;
if (kUnit.isPrereqReligion())
{
if (NULL == pCity || pCity->getReligionCount() > 0)
{
return false;
}
}
if (kUnit.getPrereqReligion() != NO_RELIGION)
{
if (NULL == pCity || !pCity->isHasReligion((ReligionTypes)(kUnit.getPrereqReligion())))
{
return false;
}
}
if (kUnit.getPrereqCorporation() != NO_CORPORATION)
{
if (NULL == pCity || !pCity->isActiveCorporation((CorporationTypes)(kUnit.getPrereqCorporation())))
{
return false;
}
}
if (kUnit.isPrereqBonuses())
{
if (kUnit.getDomainType() == DOMAIN_SEA)
{
bool bValid = false;
for (iI = 0; iI < NUM_DIRECTION_TYPES; ++iI)
{
CvPlot* pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (pLoopPlot->isWater())
{
if (pLoopPlot->area()->getNumTotalBonuses() > 0)
{
bValid = true;
break;
}
}
}
}
if (!bValid)
{
return false;
}
}
else
{
if (area()->getNumTotalBonuses() > 0)
{
return false;
}
}
}
if (isCity())
{
if (kUnit.getDomainType() == DOMAIN_SEA)
{
if (!isWater() && !isCoastalLand(kUnit.getMinAreaSize()))
{
return false;
}
}
else
{
if (area()->getNumTiles() < kUnit.getMinAreaSize())
{
return false;
}
}
}
else
{
if (area()->getNumTiles() < kUnit.getMinAreaSize())
{
return false;
}
if (kUnit.getDomainType() == DOMAIN_SEA)
{
if (!isWater())
{
return false;
}
}
else if (kUnit.getDomainType() == DOMAIN_LAND)
{
if (isWater())
{
return false;
}
}
else
{
return false;
}
}
if (!bTestVisible)
{
if (kUnit.getHolyCity() != NO_RELIGION)
{
if (NULL == pCity || !pCity->isHolyCity(((ReligionTypes)(kUnit.getHolyCity()))))
{
return false;
}
}
// 45deg: test OverrideResourceBuilding - START
if (isCity())
{
if (pCity->getNumRealBuilding((BuildingTypes)kUnit.getOverrideResourceBuilding()) > 0)
{
return true;
}
}
// 45deg: test OverrideResourceBuilding - END
if (kUnit.getPrereqAndBonus() != NO_BONUS)
{
if (NULL == pCity)
{
if (!isPlotGroupConnectedBonus(getOwnerINLINE(), (BonusTypes)kUnit.getPrereqAndBonus()))
{
return false;
}
}
else
{
if ((!pCity->hasBonus((BonusTypes)kUnit.getPrereqAndBonus())) /*&& (!pCity->getNumRealBuilding((BuildingTypes)kUnit.getOverrideResourceBuilding()) > 0)*/)
{
return false;
}
}
}
bool bRequiresBonus = false;
bool bNeedsBonus = true;
for (iI = 0; iI < GC.getNUM_UNIT_PREREQ_OR_BONUSES(); ++iI)
{
if (kUnit.getPrereqOrBonuses(iI) != NO_BONUS)
{
bRequiresBonus = true;
if (NULL == pCity)
{
if (isPlotGroupConnectedBonus(getOwnerINLINE(), (BonusTypes)kUnit.getPrereqOrBonuses(iI)))
{
bNeedsBonus = false;
break;
}
}
else
{
if (pCity->hasBonus((BonusTypes)kUnit.getPrereqOrBonuses(iI)))
/************************************************************************************************/
/* REVDCM END Performance */
/************************************************************************************************/
{
bNeedsBonus = false;
break;
}
}
}
}
if (bRequiresBonus && bNeedsBonus)
{
return false;
}
}
return true;
}
I (and WinMerge) see no difference between your code and the latest on SVN. Maybe 45° has already fixed it ... but I think the error is this:Fix for assert that triggers due to a missing check for the plot being owned. This is unlikely to fix the actual movement limit issue though
if ((getTeam() != NO_TEAM) && (GET_PLAYER(pPlot->getOwnerINLINE()).getTeam() != NO_TEAM
// K-Mod has edited this function to increase readability and robustness
void CvUnit::joinGroup(CvSelectionGroup* pSelectionGroup, bool bRemoveSelected, bool bRejoin)
{
CvSelectionGroup* pOldSelectionGroup = GET_PLAYER(getOwnerINLINE()).getSelectionGroup(getGroupID());
if (pOldSelectionGroup && pSelectionGroup == pOldSelectionGroup)
return; // attempting to join the group we are already in
CvPlot* pPlot = plot();
CvSelectionGroup* pNewSelectionGroup = pSelectionGroup;
if (pNewSelectionGroup == NULL && bRejoin)
{
pNewSelectionGroup = GET_PLAYER(getOwnerINLINE()).addSelectionGroup();
pNewSelectionGroup->init(pNewSelectionGroup->getID(), getOwnerINLINE());
}
if (pNewSelectionGroup == NULL || canJoinGroup(pPlot, pNewSelectionGroup))
{
if (pOldSelectionGroup != NULL)
{
bool bWasHead = false;
if (!isHuman())
{
if (pOldSelectionGroup->getNumUnits() > 1)
{
if (pOldSelectionGroup->getHeadUnit() == this)
{
bWasHead = true;
}
}
}
pOldSelectionGroup->removeUnit(this);
// if we were the head, if the head unitAI changed, then force the group to separate (non-humans)
if (bWasHead)
{
FAssert(pOldSelectionGroup->getHeadUnit() != NULL);
if (pOldSelectionGroup->getHeadUnit()->AI_getUnitAIType() != AI_getUnitAIType())
{
pOldSelectionGroup->AI_makeForceSeparate();
}
}
}
if ((pNewSelectionGroup != NULL) && pNewSelectionGroup->addUnit(this, false))
{
m_iGroupID = pNewSelectionGroup->getID();
}
else
{
m_iGroupID = FFreeList::INVALID_INDEX;
}
if (getGroup() != NULL)
{
// K-Mod
if (isGroupHead())
GET_PLAYER(getOwnerINLINE()).updateGroupCycle(this, false);
// K-Mod end
if (getGroup()->getNumUnits() > 1)
{
/* original bts code
getGroup()->setActivityType(ACTIVITY_AWAKE); */
// K-Mod
// For the AI, only wake the group in particular circumstances. This is to avoid AI deadlocks where they just keep grouping and ungroup indefinitely.
// If the activity type is not changed at all, then that would enable exploits such as adding new units to air patrol groups to bypass the movement conditions.
if (isHuman())
{
getGroup()->setAutomateType(NO_AUTOMATE);
getGroup()->setActivityType(ACTIVITY_AWAKE);
getGroup()->clearMissionQueue();
// K-Mod note. the mission queue has to be cleared, because when the shift key is released, the exe automatically sends the autoMission net message.
// (if the mission queue isn't cleared, the units will immediately begin their message whenever units are added using shift.)
}
else if (getGroup()->AI_getMissionAIType() == MISSIONAI_GROUP || getLastMoveTurn() == GC.getGameINLINE().getTurnSlice())
getGroup()->setActivityType(ACTIVITY_AWAKE);
else if (getGroup()->getActivityType() != ACTIVITY_AWAKE)
getGroup()->setActivityType(ACTIVITY_HOLD); // don't let them cheat.
// K-Mod end
}
/* original bts code
else
{
GET_PLAYER(getOwnerINLINE()).updateGroupCycle(this);
} */
}
if (getTeam() == GC.getGameINLINE().getActiveTeam())
{
if (pPlot != NULL)
{
pPlot->setFlagDirty(true);
}
}
if (pPlot == gDLL->getInterfaceIFace()->getSelectionPlot())
{
gDLL->getInterfaceIFace()->setDirty(PlotListButtons_DIRTY_BIT, true);
}
}
if (bRemoveSelected && IsSelected())
{
gDLL->getInterfaceIFace()->removeFromSelectionList(this);
}
}
# Erik: The line below causes a python exception
#bIsSpecial = gc.getBuildingInfo(i).getProductionCost() <= 0
# Erik: Let's try this instead
if gc.getBuildingInfo(i) == None: continue
else:
bIsSpecial = gc.getBuildingInfo(i).getProductionCost() <= 0
Also, while you're here, would you mind at looking at the code I posted above for OverrideResourceBuilding? It looks like it's working, more than 500 turns in a game right now and no issues, but I'm not sure it won't cause any problem. On the other hand devolution code for that function is similar to something I alread tried but it looks like it was causing troubles with And Or resource requirements as I explained above. Thanks.
if (isCity())
{
if (pCity->getNumRealBuilding((BuildingTypes)kUnit.getOverrideResourceBuilding()) > 0)
{
return true;
}
}
if (pCity != NULL && kUnit.getOverrideResourceBuilding() != NO_BUILDING &&
pCity->getNumActiveBuilding((BuildingTypes)kUnit.getOverrideResourceBuilding()) > 0)
{
return true;
}
// Movement Limits by 45deg - START // f1rpo: rewritten
bool CvUnit::isInsideMovementLimits(const CvPlot* pPlot) const
{
if (pPlot->isOwned() || pPlot->isRoute() || isRivalTerritory())
return true;
CvPlayer const& kOwner = GET_PLAYER(getOwner());
CvTeam const& kTeam = GET_TEAM(kOwner.getTeam());
if (kTeam.isRemoveMovementLimits())
return true;
if (kOwner.getNumCities() <= 0 || kOwner.isBarbarian())
return true;
static int const iDefaultLimit = GC.getDefineINT("BASE_EXPLORATION_RADIUS")
+ GC.getMap().getWorldSize();
int iMovementLimit = iDefaultLimit;
if (kTeam.isExtendMovementLimits())
iMovementLimit *= 2;
int iIter;
for (CvCity const* pCity = kOwner.firstCity(&iIter); pCity != NULL; pCity = kOwner.nextCity(&iIter))
{
if (plotDistance(pPlot->getX(), pPlot->getY(), pCity->getX(), pCity->getY()) <= iMovementLimit)
return true;
}
// temporary hack for pitboss
if (gDLL->IsPitbossHost() || (pPlot->isOwned() && pPlot->getTeam() >= 100))
return true;
return false;
}
bool CvUnit::isOutsideMovementLimits (const CvPlot* pPlot) const
{
return !isInsideMovementLimits(pPlot); // f1rpo: Replacing duplicate code
}
Please try to save, quit to desktop and load too because with the present dll I had experience when I started a game and "Yaay! Movement Limit is working finally"My take on Movement Limits (works OK for me if I just start a game and move some units around):
pPlot->getTeam() >= 100
If Terrain Damage is on, all units who can get damage have the same limit, regardless of domain or promotions. So in this case, workers, settlers, spies and Great People are excluded and can roam freely. Of course it's risky at the start of the game, so I see no problem with it given that those are valuable units. If Terrain Damage is off, no unit can move beyond one tile away from the limit. If for some reason they are beyond that limit, for example if your closest city gets razed, your units are bounced back to the nearest valid plot. You can explore territory outside your limit only if the tile you're moving to belongs to another civ you are at war with or have open borders with, or if it's a road. In theory, you can build a road with a worker outside your limit and then move further along that road with other units, as the tile with road becomes a valid plot. I'm not sure if a Fort acts like a city but if it doesn't I might change that.
I just uploaded rev1086, with a forced recalc to correct a bug with resources and with a fix for OverrideResourceBuilding (thanks f1rpo). In the next days I will test devolution and f1rpo changes to the code, if everything works I'll upload the changes in the next days.
I've been testing it with the Chronicles mod, but I think it's the same with just AND – units outside their limits take terrain damage. If they were actually prohibited from moving, then performance would be a bit of a concern because canMoveInto gets called by the pathfinder. (I recall an all-Python mod component that had prohibited such moves and was prohibitively slow.) AI code for avoiding terrain damage might also want to check movement limits at every pathfinding step, but I don't think that's currently the case.Here's an old post where I explain how Movement Limits is supposed to work. [...]
Or teammates. So perhaps:[...]
- What about proximity to vassals ?
for (int i = 0; i < MAX_CIV_PLAYERS; i++)
{
CvPlayer const& kLoopPlayer = GET_PLAYER((PlayerTypes)i);
if (!kLoopPlayer.isAlive())
continue;
if (kLoopPlayer.getTeam() == kOwner.getTeam() ||
GET_TEAM(kLoopPlayer.getTeam()).isVassal(kOwner.getTeam()))
{
int iIter;
for (CvCity const* pCity = kOwner.firstCity(&iIter); pCity != NULL;
pCity = kOwner.nextCity(&iIter))
{
if (plotDistance(pPlot->getX(), pPlot->getY(),
pCity->getX(), pCity->getY()) <= iMovementLimit)
{
return true;
}
}
}
}
In terms of supplies reaching the unit, that would sure be more realistic. Well, I don't think using air distance is bad.- What about a unit being in a different area than the closest city. Crossing an area should arguably be considered more "limiting".
- Probably need to do full pathfinding to capture the effect of borders, impassable plots etc.
Sure. Credits: No need, but please feel free to; in my case, it's really a tiny contribution.is that ok with you if I add your code to the dll and add your names to the credits page of AND2? Thanks again.
Can't reproduce that. If something doesn't get saved properly, then I doubt that my changes have done anything to fix that. I guess it's possible that thePlease try to save, quit to desktop and load too because with the present dll I had experience when I started a game and "Yaay! Movement Limit is working finally"" and than I quit and loaded later and than "It's not working! Again!
![]()
"
How it works for Temple, I think, is that the tech requirement is set in Civ4SpecialBuildingInfos.xml.[...] I'd like to hide that "Allows construction of four lines of so and so..." and just put there a simple "Allows construction of guild halls." using the help tag. [...]