// plot.cpp
#include "CvGameCoreDLL.h"
#include "CvPlot.h"
#include "CvCity.h"
#include "CvUnit.h"
#include "CvGlobals.h"
#include "CvArea.h"
#include "CvGameAI.h"
#include "CvDLLInterfaceIFaceBase.h"
#include "CvDLLSymbolIFaceBase.h"
#include "CvDLLEntityIFaceBase.h"
#include "CvDLLPlotBuilderIFaceBase.h"
#include "CvDLLEngineIFaceBase.h"
#include "CvDLLFlagEntityIFaceBase.h"
#include "CvMap.h"
#include "CvPlayerAI.h"
#include "CvTeamAI.h"
#include "CvGameCoreUtils.h"
#include "CvRandom.h"
#include "CvDLLFAStarIFaceBase.h"
#include "CvDLLEventReporterIFaceBase.h"
#include "CvInfos.h"
#include "FProfiler.h"
#include "CvArtFileMgr.h"
#define STANDARD_MINIMAP_ALPHA (0.6f)
// Public Functions...
CvPlot::CvPlot()
{
int iI;
m_szScriptData = NULL;
m_paiBuildProgress = NULL;
m_pFeatureSymbol = NULL;
m_pPlotBuilder = NULL;
m_pRouteSymbol = NULL;
m_pRiverSymbol = NULL;
m_pFlagSymbol = NULL;
m_pFlagSymbolOffset = NULL;
m_pCenterUnit = NULL;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
m_apaiCultureRangeCities[iI] = NULL;
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
m_apaiInvisibleVisibilityCount[iI] = NULL;
}
reset(0, 0, true);
}
CvPlot::~CvPlot()
{
uninit();
}
void CvPlot::init(int iX, int iY)
{
//--------------------------------
// Init saved data
reset(iX, iY);
//--------------------------------
// Init non-saved data
//--------------------------------
// Init other game data
}
void CvPlot::uninit()
{
int iI;
SAFE_DELETE_ARRAY(m_szScriptData);
SAFE_DELETE_ARRAY(m_paiBuildProgress);
gDLL->getFeatureIFace()->destroy(m_pFeatureSymbol);
if(m_pPlotBuilder) {
gDLL->getPlotBuilderIFace()->destroy(m_pPlotBuilder);
}
gDLL->getRouteIFace()->destroy(m_pRouteSymbol);
gDLL->getRiverIFace()->destroy(m_pRiverSymbol);
gDLL->getFlagEntityIFace()->destroy(m_pFlagSymbol);
gDLL->getFlagEntityIFace()->destroy(m_pFlagSymbolOffset);
m_pCenterUnit = NULL;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
SAFE_DELETE_ARRAY(m_apaiCultureRangeCities[iI]);
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
SAFE_DELETE_ARRAY(m_apaiInvisibleVisibilityCount[iI]);
}
m_units.clear();
deleteAllSymbols();
}
// FUNCTION: reset()
// Initializes data members that are serialized.
void CvPlot::reset(int iX, int iY, bool bConstructorCall)
{
int iI, iJ;
//--------------------------------
// Uninit class
uninit();
m_iX = iX;
m_iY = iY;
m_iArea = FFreeList::INVALID_INDEX;
m_iFeatureVariety = 0;
m_iOwnershipDuration = 0;
m_iImprovementDuration = 0;
m_iUpgradeProgress = 0;
m_iForceUnownedTimer = 0;
m_iCityRadiusCount = 0;
m_iRiverID = -1;
m_iMinOriginalStartDist = -1;
m_iReconCount = 0;
m_iRiverCrossingCount = 0;
m_bStartingPlot = false;
m_bHills = false;
m_bNOfRiver = false;
m_bWOfRiver = false;
m_bIrrigated = false;
m_bPotentialCityWork = false;
m_bShowCitySymbols = false;
m_bFlagDirty = false;
m_bPlotLayoutDirty = false;
m_bLayoutStateWorked = false;
m_eOwner = NO_PLAYER;
m_ePlotType = PLOT_OCEAN;
m_eTerrainType = NO_TERRAIN;
m_eFeatureType = NO_FEATURE;
m_eBonusType = NO_BONUS;
m_eImprovementType = NO_IMPROVEMENT;
m_eRouteType = NO_ROUTE;
m_eRiverNSDirection = NO_CARDINALDIRECTION;
m_eRiverWEDirection = NO_CARDINALDIRECTION;
m_plotCity.reset();
m_workingCity.reset();
m_workingCityOverride.reset();
for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
m_aiYield[iI] = 0;
}
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
m_aiCulture[iI] = 0;
m_aiFoundValue[iI] = 0;
m_aiPlayerCityRadiusCount[iI] = 0;
m_aiPlotGroup[iI] = FFreeList::INVALID_INDEX;
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
m_aiVisibilityCount[iI] = 0;
m_aiStolenVisibilityCount[iI] = 0;
m_aiRevealedOwner[iI] = -1;
}
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
m_abRiverCrossing[iI] = false;
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
m_abRevealed[iI] = false;
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
m_aeRevealedImprovementType[iI] = NO_IMPROVEMENT;
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
m_aeRevealedRouteType[iI] = NO_ROUTE;
}
if (!bConstructorCall)
{
FAssertMsg(m_paiBuildProgress==NULL, "about to leak memory, CvPlayer::m_paiBuildProgress");
m_paiBuildProgress = new short [GC.getNumBuildInfos()];
for (iI = 0; iI < GC.getNumBuildInfos();iI++)
{
m_paiBuildProgress[iI] = 0;
}
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
FAssertMsg(m_apaiCultureRangeCities[iI]==NULL, "about to leak memory, CvPlot::m_apaiCultureRangeCities");
FAssertMsg((0 < GC.getNumCultureLevelInfos()), "GC.getNumCultureLevelInfos() is not greater than zero but an array is being allocated in CvPlot::reset");
m_apaiCultureRangeCities[iI] = new char[GC.getNumCultureLevelInfos()];
for (iJ = 0; iJ < GC.getNumCultureLevelInfos(); iJ++)
{
m_apaiCultureRangeCities[iI][iJ] = 0;
}
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
FAssertMsg(m_apaiInvisibleVisibilityCount[iI]==NULL, "about to leak memory, CvPlot::m_apaiInvisibleVisibilityCount");
FAssertMsg((0 < GC.getNumInvisibleInfos()), "GC.getNumInvisibleInfos() is not greater than zero but an array is being allocated in CvPlot::reset");
m_apaiInvisibleVisibilityCount[iI] = new short[GC.getNumInvisibleInfos()];
for (iJ = 0; iJ < GC.getNumInvisibleInfos(); iJ++)
{
m_apaiInvisibleVisibilityCount[iI][iJ] = 0;
}
}
}
}
//////////////////////////////////////
// graphical only setup
//////////////////////////////////////
void CvPlot::setupGraphical()
{
PROFILE_FUNC();
if (!GC.IsGraphicsInitialized())
{
return;
}
updateSymbols();
updateFeatureSymbol();
updateRiverSymbol();
updateMinimapColor();
updateVisibility();
}
void CvPlot::erase()
{
CLLNode<IDInfo>* pUnitNode;
CvCity* pCity;
CvUnit* pLoopUnit;
CLinkList<IDInfo> oldUnits;
// kill units
oldUnits.clear();
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
oldUnits.insertAtEnd(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
}
pUnitNode = oldUnits.head();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = oldUnits.next(pUnitNode);
if (pLoopUnit != NULL)
{
pLoopUnit->kill(false);
}
}
// kill cities
pCity = getPlotCity();
if (pCity != NULL)
{
pCity->kill();
}
setBonusType(NO_BONUS);
setImprovementType(NO_IMPROVEMENT);
setRouteType(NO_ROUTE);
setFeatureType(NO_FEATURE);
// disable rivers
setNOfRiver(false, NO_CARDINALDIRECTION);
setWOfRiver(false, NO_CARDINALDIRECTION);
setRiverID(-1);
}
float CvPlot::getPointX() const
{
return GC.getMapINLINE().plotXToPointX(getX_INLINE());
}
float CvPlot::getPointY() const
{
return GC.getMapINLINE().plotYToPointY(getY_INLINE());
}
NiPoint3 CvPlot::getPoint() const
{
NiPoint3 pt3Point;
pt3Point.x = getPointX();
pt3Point.y = getPointY();
pt3Point.z = 0.0f;
pt3Point.z = gDLL->getEngineIFace()->GetHeightmapZ(pt3Point);
return pt3Point;
}
float CvPlot::getSymbolSize() const
{
if (isVisibleWorked())
{
if (isShowCitySymbols())
{
return 1.6f;
}
else
{
return 1.2f;
}
}
else
{
if (isShowCitySymbols())
{
return 1.2f;
}
else
{
return 0.8f;
}
}
}
float CvPlot::getSymbolOffsetX(int iOffset) const
{
return ((40.0f + (((float)iOffset) * 28.0f * getSymbolSize())) - (GC.getDefineFLOAT( "PLOT_SIZE" ) / 2.0f));
}
float CvPlot::getSymbolOffsetY(int iOffset) const
{
return (-(GC.getDefineFLOAT( "PLOT_SIZE" ) / 2.0f) + 50.0f);
}
TeamTypes CvPlot::getTeam() const
{
if (isOwned())
{
return GET_PLAYER(getOwnerINLINE()).getTeam();
}
else
{
return NO_TEAM;
}
}
void CvPlot::doTurn()
{
PROFILE_FUNC();
if (getForceUnownedTimer() > 0)
{
changeForceUnownedTimer(-1);
}
if (isOwned())
{
changeOwnershipDuration(1);
}
if (getImprovementType() != NO_IMPROVEMENT)
{
changeImprovementDuration(1);
}
doFeature();
doCulture();
verifyUnitValidPlot();
// XXX
#ifdef _DEBUG
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
FAssertMsg(pLoopUnit->atPlot(this), "pLoopUnit is expected to be at the current plot instance");
}
}
#endif
// XXX
}
void CvPlot::doImprovement()
{
PROFILE_FUNC();
CvCity* pCity;
wchar szBuffer[1024];
int iI;
FAssert(isBeingWorked());
FAssert(isOwned());
if (getImprovementType() != NO_IMPROVEMENT)
{
if (getBonusType() == NO_BONUS)
{
FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlot::doImprovement");
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
if (GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getBonusInfo((BonusTypes) iI).getTechReveal())))
{
if (GC.getImprovementInfo(getImprovementType()).getImprovementBonusDiscoverRand(iI) > 0)
{
if (GC.getGameINLINE().getSorenRandNum(GC.getImprovementInfo(getImprovementType()).getImprovementBonusDiscoverRand(iI), "Bonus Discovery") == 0)
{
setBonusType((BonusTypes)iI);
pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE(), NO_TEAM, false);
if (pCity != NULL)
{
swprintf(szBuffer, gDLL->getText("TXT_KEY_MISC_DISCOVERED_NEW_RESOURCE", GC.getBonusInfo((BonusTypes) iI).getTextKeyWide(), pCity->getNameKey()).GetCString());
gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MINOR_EVENT, GC.getBonusInfo((BonusTypes) iI).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE(), true, true);
}
break;
}
}
}
}
}
if (GC.getImprovementInfo(getImprovementType()).getImprovementUpgrade() != NO_IMPROVEMENT)
{
changeUpgradeProgress(GET_PLAYER(getOwnerINLINE()).getImprovementUpgradeRate());
if (getUpgradeProgress() >= GC.getGameINLINE().getImprovementUpgradeTime(getImprovementType()))
{
setImprovementType((ImprovementTypes)(GC.getImprovementInfo(getImprovementType()).getImprovementUpgrade()));
}
}
}
}
void CvPlot::updateCulture()
{
if (!isCity())
{
setOwner(calculateCulturalOwner());
}
}
void CvPlot::updateFog()
{
PROFILE_FUNC();
if (!GC.IsGraphicsInitialized())
{
return;
}
FAssert(GC.getGameINLINE().getActiveTeam() != NO_TEAM);
if (isRevealed(GC.getGameINLINE().getActiveTeam(), false))
{
if (gDLL->getInterfaceIFace()->isBareMapMode())
{
gDLL->getEngineIFace()->LightenVisibility(getFOWIndex());
}
else
{
if (gDLL->getInterfaceIFace()->isCityScreenUp() && (gDLL->getInterfaceIFace()->getHeadSelectedCity() != getWorkingCity()))
{
gDLL->getEngineIFace()->DarkenVisibility(getFOWIndex());
}
else if (isActiveVisible(false))
{
gDLL->getEngineIFace()->LightenVisibility(getFOWIndex());
}
else
{
gDLL->getEngineIFace()->DarkenVisibility(getFOWIndex());
}
}
}
else
{
gDLL->getEngineIFace()->BlackenVisibility(getFOWIndex());
}
}
void CvPlot::updateVisibility()
{
PROFILE("CvPlot::updateVisibility");
if (!GC.IsGraphicsInitialized())
{
return;
}
setLayoutDirty(true);
updateSymbolVisibility();
updateFeatureSymbolVisibility();
updateRouteSymbol();
CvCity* pCity = getPlotCity();
if (pCity != NULL)
{
pCity->updateVisibility();
}
}
void CvPlot::updateSymbolDisplay()
{
PROFILE_FUNC();
CvSymbol* pLoopSymbol;
int iLoop;
if (!GC.IsGraphicsInitialized())
{
return;
}
for (iLoop = 0; iLoop < getNumSymbols(); iLoop++)
{
pLoopSymbol = getSymbol(iLoop);
if (pLoopSymbol != NULL)
{
if (isShowCitySymbols())
{
gDLL->getSymbolIFace()->setAlpha(pLoopSymbol, (isVisibleWorked()) ? 1.0f : 0.8f);
}
else
{
gDLL->getSymbolIFace()->setAlpha(pLoopSymbol, (isVisibleWorked()) ? 0.8f : 0.6f);
}
gDLL->getSymbolIFace()->setScale(pLoopSymbol, getSymbolSize());
gDLL->getSymbolIFace()->updatePosition(pLoopSymbol);
}
}
}
void CvPlot::updateSymbolVisibility()
{
PROFILE_FUNC();
CvSymbol* pLoopSymbol;
int iLoop;
if (!GC.IsGraphicsInitialized())
{
return;
}
for (iLoop = 0; iLoop < getNumSymbols(); iLoop++)
{
pLoopSymbol = getSymbol(iLoop);
if (pLoopSymbol != NULL)
{
if (isRevealed(GC.getGameINLINE().getActiveTeam(), true) &&
(isShowCitySymbols() ||
(gDLL->getInterfaceIFace()->isShowYields() && !(gDLL->getInterfaceIFace()->isCityScreenUp()))))
{
gDLL->getSymbolIFace()->Hide(pLoopSymbol, false);
}
else
{
gDLL->getSymbolIFace()->Hide(pLoopSymbol, true);
}
}
}
}
void CvPlot::updateSymbols()
{
PROFILE_FUNC();
if (!GC.IsGraphicsInitialized())
{
return;
}
deleteAllSymbols();
int yieldAmounts[NUM_YIELD_TYPES];
int maxYield = 0;
for (int iYieldType = 0; iYieldType < NUM_YIELD_TYPES; iYieldType++)
{
int iYield = calculateYield(((YieldTypes)iYieldType), true);
yieldAmounts[iYieldType] = iYield;
if(iYield>maxYield)
{
maxYield = iYield;
}
}
if(maxYield>0)
{
int maxYieldStack = GC.getDefineINT("MAX_YIELD_STACK");
int layers = maxYield /maxYieldStack + 1;
CvSymbol *pSymbol= NULL;
for(int i=0;i<layers;i++)
{
pSymbol = addSymbol();
for (int iYieldType = 0; iYieldType < NUM_YIELD_TYPES; iYieldType++)
{
int iYield = yieldAmounts[iYieldType] - (maxYieldStack * i);
LIMIT_RANGE(0,iYield, maxYieldStack);
if(yieldAmounts[iYieldType])
{
gDLL->getSymbolIFace()->setTypeYield(pSymbol,iYieldType,iYield);
}
}
}
for(int i=0;i<getNumSymbols();i++)
{
SymbolTypes eSymbol = (SymbolTypes)0;
pSymbol = getSymbol(i);
gDLL->getSymbolIFace()->init(pSymbol, gDLL->getSymbolIFace()->getID(pSymbol), i, eSymbol, this);
}
}
updateSymbolDisplay();
updateSymbolVisibility();
}
void CvPlot::updateMinimapColor()
{
PROFILE_FUNC();
if (!GC.IsGraphicsInitialized())
{
return;
}
gDLL->getInterfaceIFace()->setMinimapColor(MINIMAPMODE_TERRITORY, getX_INLINE(), getY_INLINE(), plotMinimapColor(), STANDARD_MINIMAP_ALPHA);
}
void CvPlot::updateCenterUnit()
{
PROFILE_FUNC();
if (!GC.IsGraphicsInitialized())
{
return;
}
if (!isActiveVisible(true))
{
setCenterUnit(NULL);
return;
}
setCenterUnit(getSelectedUnit());
if (getCenterUnit() == NULL)
{
setCenterUnit(getBestDefender(GC.getGameINLINE().getActivePlayer(), NO_PLAYER, NULL, false, false, true));
}
if (getCenterUnit() == NULL)
{
setCenterUnit(getBestDefender(GC.getGameINLINE().getActivePlayer()));
}
if (getCenterUnit() == NULL)
{
setCenterUnit(getBestDefender(NO_PLAYER, GC.getGameINLINE().getActivePlayer(), gDLL->getInterfaceIFace()->getHeadSelectedUnit(), true));
}
if (getCenterUnit() == NULL)
{
setCenterUnit(getBestDefender(NO_PLAYER, GC.getGameINLINE().getActivePlayer(), gDLL->getInterfaceIFace()->getHeadSelectedUnit()));
}
if (getCenterUnit() == NULL)
{
setCenterUnit(getBestDefender(NO_PLAYER, GC.getGameINLINE().getActivePlayer()));
}
}
void CvPlot::verifyUnitValidPlot()
{
PROFILE_FUNC();
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
CLinkList<IDInfo> oldUnits;
oldUnits.clear();
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
oldUnits.insertAtEnd(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
}
pUnitNode = oldUnits.head();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = oldUnits.next(pUnitNode);
if (pLoopUnit != NULL)
{
if (pLoopUnit->atPlot(this))
{
if (!(pLoopUnit->isCargo()))
{
if (!(pLoopUnit->isCombat()))
{
if (!(pLoopUnit->canEnterTerritory(getTeam())))
{
pLoopUnit->jumpToNearestValidPlot();
}
}
}
}
}
}
pUnitNode = oldUnits.head();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = oldUnits.next(pUnitNode);
if (pLoopUnit != NULL)
{
if (pLoopUnit->atPlot(this))
{
if (!(pLoopUnit->isCombat()))
{
if (pLoopUnit->getTeam() != getTeam())
{
if (plotCheck(PUF_isEnemy, pLoopUnit->getOwnerINLINE()) != NULL)
{
if (!(pLoopUnit->alwaysInvisible()))
{
pLoopUnit->jumpToNearestValidPlot();
}
}
}
}
}
}
}
}
void CvPlot::nukeExplosion(int iRange, CvUnit* pNukeUnit)
{
CLLNode<IDInfo>* pUnitNode;
CvCity* pLoopCity;
CvUnit* pLoopUnit;
CvPlot* pLoopPlot;
CLinkList<IDInfo> oldUnits;
CvWString szBuffer;
int iNukeDamage;
int iNukedPopulation;
int iDX, iDY;
int iI;
GC.getGameINLINE().changeNukesExploded(1);
for (iDX = -(iRange); iDX <= iRange; iDX++)
{
for (iDY = -(iRange); iDY <= iRange; iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
if (pLoopPlot != NULL)
{
// if we remove roads, don't remove them on the city... XXX
pLoopCity = pLoopPlot->getPlotCity();
if (pLoopCity == NULL)
{
if (!(pLoopPlot->isWater()) && !(pLoopPlot->isImpassable()))
{
if (GC.getGameINLINE().getSorenRandNum(100, "Nuke Fallout") < GC.getDefineINT("NUKE_FALLOUT_PROB"))
{
pLoopPlot->setImprovementType(NO_IMPROVEMENT);
pLoopPlot->setFeatureType((FeatureTypes)(GC.getDefineINT("NUKE_FEATURE")));
}
}
}
oldUnits.clear();
pUnitNode = pLoopPlot->headUnitNode();
while (pUnitNode != NULL)
{
oldUnits.insertAtEnd(pUnitNode->m_data);
pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
}
pUnitNode = oldUnits.head();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = oldUnits.next(pUnitNode);
if (pLoopUnit != NULL)
{
if (pLoopUnit != pNukeUnit)
{
if (!(pLoopUnit->isNukeImmune()))
{
iNukeDamage = (GC.getDefineINT("NUKE_UNIT_DAMAGE_BASE") + GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("NUKE_UNIT_DAMAGE_RAND_1"), "Nuke Damage 1") + GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("NUKE_UNIT_DAMAGE_RAND_2"), "Nuke Damage 2"));
if (pLoopCity != NULL)
{
iNukeDamage *= max(0, (pLoopCity->getNukeModifier() + 100));
iNukeDamage /= 100;
}
if (pLoopUnit->canFight())
{
pLoopUnit->changeDamage(iNukeDamage, ((pNukeUnit != NULL) ? pNukeUnit->getOwnerINLINE() : NO_PLAYER));
}
else if (iNukeDamage >= GC.getDefineINT("NUKE_NON_COMBAT_DEATH_THRESHOLD"))
{
pLoopUnit->kill(false, ((pNukeUnit != NULL) ? pNukeUnit->getOwnerINLINE() : NO_PLAYER));
}
}
}
}
}
if (pLoopCity != NULL)
{
for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
{
if (pLoopCity->isHasRealBuilding((BuildingTypes)iI))
{
if (!(GC.getBuildingInfo((BuildingTypes) iI).isNukeImmune()))
{
if (GC.getGameINLINE().getSorenRandNum(100, "Building Nuked") < GC.getDefineINT("NUKE_BUILDING_DESTRUCTION_PROB"))
{
pLoopCity->setHasRealBuilding(((BuildingTypes)iI), false);
}
}
}
}
iNukedPopulation = ((pLoopCity->getPopulation() * (GC.getDefineINT("NUKE_POPULATION_DEATH_BASE") + GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("NUKE_POPULATION_DEATH_RAND_1"), "Population Nuked 1") + GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("NUKE_POPULATION_DEATH_RAND_2"), "Population Nuked 2"))) / 100);
iNukedPopulation *= max(0, (pLoopCity->getNukeModifier() + 100));
iNukedPopulation /= 100;
pLoopCity->changePopulation(-(min((pLoopCity->getPopulation() - 1), iNukedPopulation)));
}
}
}
}
}
bool CvPlot::isConnectedTo(const CvCity* pCity) const
{
return ((getPlotGroup(getOwnerINLINE()) == pCity->plotGroup(getOwnerINLINE())) || (getPlotGroup(pCity->getOwnerINLINE()) == pCity->plotGroup(pCity->getOwnerINLINE())));
}
bool CvPlot::isConnectedToCapital(PlayerTypes ePlayer) const
{
CvCity* pCapitalCity;
if (ePlayer == NO_PLAYER)
{
ePlayer = getOwnerINLINE();
}
if (ePlayer != NO_PLAYER)
{
pCapitalCity = GET_PLAYER(ePlayer).getCapitalCity();
if (pCapitalCity != NULL)
{
return isConnectedTo(pCapitalCity);
}
}
return false;
}
int CvPlot::getPlotGroupConnectedBonus(PlayerTypes ePlayer, BonusTypes eBonus) const
{
CvPlotGroup* pPlotGroup;
FAssertMsg(ePlayer != NO_PLAYER, "Player is not assigned a valid value");
FAssertMsg(eBonus != NO_BONUS, "Bonus is not assigned a valid value");
pPlotGroup = getPlotGroup(ePlayer);
if (pPlotGroup != NULL)
{
return pPlotGroup->getNumBonuses(eBonus);
}
else
{
return 0;
}
}
bool CvPlot::isPlotGroupConnectedBonus(PlayerTypes ePlayer, BonusTypes eBonus) const
{
return (getPlotGroupConnectedBonus(ePlayer, eBonus) > 0);
}
bool CvPlot::isAdjacentPlotGroupConnectedBonus(PlayerTypes ePlayer, BonusTypes eBonus) const
{
CvPlot* pAdjacentPlot;
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->isPlotGroupConnectedBonus(ePlayer, eBonus))
{
return true;
}
}
}
return false;
}
void CvPlot::updatePlotGroupBonus(bool bAdd)
{
PROFILE_FUNC();
CvCity* pPlotCity;
CvPlotGroup* pPlotGroup;
BonusTypes eNonObsoleteBonus;
int iI;
if (!isOwned())
{
return;
}
pPlotGroup = getPlotGroup(getOwnerINLINE());
if (pPlotGroup != NULL)
{
pPlotCity = getPlotCity();
if (pPlotCity != NULL)
{
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
if ((GC.getBonusInfo((BonusTypes)iI).getTechObsolete() == NO_TECH) || !(GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getBonusInfo((BonusTypes)iI).getTechObsolete()))))
{
pPlotGroup->changeNumBonuses(((BonusTypes)iI), (pPlotCity->getFreeBonus((BonusTypes)iI) * ((bAdd) ? 1 : -1)));
}
}
if (pPlotCity->isCapital())
{
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
pPlotGroup->changeNumBonuses(((BonusTypes)iI), (GET_PLAYER(getOwnerINLINE()).getBonusExport((BonusTypes)iI) * ((bAdd) ? -1 : 1)));
pPlotGroup->changeNumBonuses(((BonusTypes)iI), (GET_PLAYER(getOwnerINLINE()).getBonusImport((BonusTypes)iI) * ((bAdd) ? 1 : -1)));
}
}
}
eNonObsoleteBonus = getNonObsoleteBonusType(getTeam());
if (eNonObsoleteBonus != NO_BONUS)
{
if (((pPlotCity != NULL) && GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getBonusInfo(eNonObsoleteBonus).getTechCityTrade()))) ||
((getImprovementType() != NO_IMPROVEMENT) && GC.getImprovementInfo(getImprovementType()).isImprovementBonusTrade(eNonObsoleteBonus)))
{
if ((pPlotGroup != NULL) && isBonusNetwork(getTeam()))
{
pPlotGroup->changeNumBonuses(eNonObsoleteBonus, ((bAdd) ? 1 : -1));
}
}
}
}
}
bool CvPlot::isAdjacentToArea(const CvArea* pArea) const
{
PROFILE_FUNC();
CvPlot* pAdjacentPlot;
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->area() == pArea)
{
return true;
}
}
}
return false;
}
bool CvPlot::shareAdjacentArea(const CvPlot* pPlot) const
{
PROFILE_FUNC();
CvArea* pCurrArea;
CvArea* pLastArea;
CvPlot* pAdjacentPlot;
int iI;
pLastArea = NULL;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
pCurrArea = pAdjacentPlot->area();
if (pCurrArea != pLastArea)
{
if (pPlot->isAdjacentToArea(pCurrArea))
{
return true;
}
pLastArea = pCurrArea;
}
}
}
return false;
}
bool CvPlot::isAdjacentToLand() const
{
PROFILE_FUNC();
CvPlot* pAdjacentPlot;
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (!(pAdjacentPlot->isWater()))
{
return true;
}
}
}
return false;
}
bool CvPlot::isCoastalLand() const
{
PROFILE_FUNC();
CvPlot* pAdjacentPlot;
int iI;
if (isWater())
{
return false;
}
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->isWater())
{
return true;
}
}
}
return false;
}
bool CvPlot::isVisibleWorked() const
{
if (isBeingWorked())
{
if ((getTeam() == GC.getGameINLINE().getActiveTeam()) || GC.getGameINLINE().isDebugMode())
{
return true;
}
}
return false;
}
bool CvPlot::isWithinTeamCityRadius(TeamTypes eTeam, PlayerTypes eIgnorePlayer) const
{
PROFILE_FUNC();
int iI;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
if (GET_PLAYER((PlayerTypes)iI).getTeam() == eTeam)
{
if ((eIgnorePlayer == NO_PLAYER) || (((PlayerTypes)iI) != eIgnorePlayer))
{
if (isPlayerCityRadius((PlayerTypes)iI))
{
return true;
}
}
}
}
}
return false;
}
bool CvPlot::isLake() const
{
CvArea* pArea;
pArea = area();
if (pArea != NULL)
{
return pArea->isLake();
}
return false;
}
// XXX if this changes need to call updateIrrigated() and pCity->updateFreshWaterHealth()
// XXX precalculate this???
bool CvPlot::isFreshWater() const
{
CvPlot* pLoopPlot;
int iDX, iDY;
if (isWater())
{
return false;
}
if (isImpassable())
{
return false;
}
if (isRiver())
{
return true;
}
for (iDX = -1; iDX <= 1; iDX++)
{
for (iDY = -1; iDY <= 1; iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
if (pLoopPlot != NULL)
{
if (pLoopPlot->isLake())
{
return true;
}
if (pLoopPlot->getFeatureType() != NO_FEATURE)
{
if (GC.getFeatureInfo(pLoopPlot->getFeatureType()).isAddsFreshWater())
{
return true;
}
}
}
}
}
return false;
}
bool CvPlot::isPotentialIrrigation() const
{
if ((isCity() && !isHills()) || ((getImprovementType() != NO_IMPROVEMENT) && (GC.getImprovementInfo(getImprovementType()).isCarriesIrrigation())))
{
if ((getTeam() != NO_TEAM) && GET_TEAM(getTeam()).isIrrigation())
{
return true;
}
}
return false;
}
bool CvPlot::canHavePotentialIrrigation() const
{
int iI;
if (isCity() && !isHills())
{
return true;
}
for (iI = 0; iI < GC.getNumImprovementInfos(); iI++)
{
if (GC.getImprovementInfo((ImprovementTypes)iI).isCarriesIrrigation())
{
if (canHaveImprovement(((ImprovementTypes)iI), NO_TEAM, true))
{
return true;
}
}
}
return false;
}
bool CvPlot::isIrrigationAvailable(bool bIgnoreSelf) const
{
CvPlot* pAdjacentPlot;
int iI;
if (!bIgnoreSelf && isIrrigated())
{
return true;
}
if (isFreshWater())
{
return true;
}
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->isIrrigated())
{
return true;
}
}
}
return false;
}
bool CvPlot::isRiverMask() const
{
CvPlot* pPlot;
if (isNOfRiver())
{
return true;
}
if (isWOfRiver())
{
return true;
}
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_EAST);
if ((pPlot != NULL) && pPlot->isNOfRiver())
{
return true;
}
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_SOUTH);
if ((pPlot != NULL) && pPlot->isWOfRiver())
{
return true;
}
return false;
}
bool CvPlot::isRiverCrossingFlowClockwise(DirectionTypes eDirection) const
{
CvPlot *pPlot;
switch(eDirection)
{
case DIRECTION_NORTH:
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTH);
if (pPlot != NULL)
{
return (pPlot->getRiverWEDirection() == CARDINALDIRECTION_EAST);
}
break;
case DIRECTION_EAST:
return (getRiverNSDirection() == CARDINALDIRECTION_SOUTH);
break;
case DIRECTION_SOUTH:
return (getRiverWEDirection() == CARDINALDIRECTION_WEST);
break;
case DIRECTION_WEST:
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_WEST);
if(pPlot != NULL)
{
return (pPlot->getRiverNSDirection() == CARDINALDIRECTION_NORTH);
}
break;
default:
FAssert(false);
break;
}
return false;
}
bool CvPlot::isRiverSide() const
{
CvPlot* pLoopPlot;
int iI;
for (iI = 0; iI < NUM_CARDINALDIRECTION_TYPES; iI++)
{
pLoopPlot = plotCardinalDirection(getX_INLINE(), getY_INLINE(), ((CardinalDirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (isRiverCrossing(directionXY(this, pLoopPlot)))
{
return true;
}
}
}
return false;
}
bool CvPlot::isRiver() const
{
return (getRiverCrossingCount() > 0);
}
bool CvPlot::isRiverConnection(DirectionTypes eDirection) const
{
if (eDirection == NO_DIRECTION)
{
return false;
}
switch (eDirection)
{
case DIRECTION_NORTH:
return (isRiverCrossing(DIRECTION_EAST) || isRiverCrossing(DIRECTION_WEST));
break;
case DIRECTION_NORTHEAST:
return (isRiverCrossing(DIRECTION_NORTH) || isRiverCrossing(DIRECTION_EAST));
break;
case DIRECTION_EAST:
return (isRiverCrossing(DIRECTION_NORTH) || isRiverCrossing(DIRECTION_SOUTH));
break;
case DIRECTION_SOUTHEAST:
return (isRiverCrossing(DIRECTION_SOUTH) || isRiverCrossing(DIRECTION_EAST));
break;
case DIRECTION_SOUTH:
return (isRiverCrossing(DIRECTION_EAST) || isRiverCrossing(DIRECTION_WEST));
break;
case DIRECTION_SOUTHWEST:
return (isRiverCrossing(DIRECTION_SOUTH) || isRiverCrossing(DIRECTION_WEST));
break;
case DIRECTION_WEST:
return (isRiverCrossing(DIRECTION_NORTH) || isRiverCrossing(DIRECTION_SOUTH));
break;
case DIRECTION_NORTHWEST:
return (isRiverCrossing(DIRECTION_NORTH) || isRiverCrossing(DIRECTION_WEST));
break;
default:
FAssert(false);
break;
}
return false;
}
CvPlot* CvPlot::getNearestLandPlotInternal(int iDistance) const
{
if (iDistance > GC.getMapINLINE().getGridHeightINLINE() && iDistance > GC.getMapINLINE().getGridWidthINLINE())
{
return NULL;
}
for (int iDX = -iDistance; iDX <= iDistance; iDX++)
{
for (int iDY = -iDistance; iDY <= iDistance; iDY++)
{
if (abs(iDX) + abs(iDY) == iDistance)
{
CvPlot* pPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
if (pPlot != NULL)
{
if (!pPlot->isWater())
{
return pPlot;
}
}
}
}
}
return getNearestLandPlotInternal(iDistance + 1);
}
int CvPlot::getNearestLandArea() const
{
CvPlot* pPlot = getNearestLandPlot();
return pPlot ? pPlot->getArea() : -1;
}
CvPlot* CvPlot::getNearestLandPlot() const
{
return getNearestLandPlotInternal(0);
}
int CvPlot::seeFromLevel(TeamTypes eTeam) const
{
int iLevel;
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
iLevel = GC.getTerrainInfo(getTerrainType()).getSeeFromLevel();
if (isPeak())
{
iLevel += GC.getDefineINT("PEAK_SEE_FROM_CHANGE");
}
if (isHills())
{
iLevel += GC.getDefineINT("HILLS_SEE_FROM_CHANGE");
}
if (isWater())
{
iLevel += GC.getDefineINT("SEAWATER_SEE_FROM_CHANGE");
if (GET_TEAM(eTeam).isExtraWaterSeeFrom())
{
iLevel++;
}
}
return iLevel;
}
int CvPlot::seeThroughLevel() const
{
int iLevel;
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
iLevel = GC.getTerrainInfo(getTerrainType()).getSeeThroughLevel();
if (getFeatureType() != NO_FEATURE)
{
iLevel += GC.getFeatureInfo(getFeatureType()).getSeeThroughChange();
}
if (isPeak())
{
iLevel += GC.getDefineINT("PEAK_SEE_THROUGH_CHANGE");
}
if (isHills())
{
iLevel += GC.getDefineINT("HILLS_SEE_THROUGH_CHANGE");
}
if (isWater())
{
iLevel += GC.getDefineINT("SEAWATER_SEE_FROM_CHANGE");
}
return iLevel;
}
void CvPlot::changeSeeFromSight(TeamTypes eTeam, DirectionTypes eDirection, int iFromLevel, bool bIncrement, InvisibleTypes eSeeInvisible)
{
CvPlot* pPlot;
int iThroughLevel;
iThroughLevel = seeThroughLevel();
if (iFromLevel >= iThroughLevel)
{
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), eDirection);
if (pPlot != NULL)
{
if ((iFromLevel > iThroughLevel) || (pPlot->seeFromLevel(eTeam) > iFromLevel))
{
pPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
}
}
}
}
void CvPlot::changeAdjacentSight(TeamTypes eTeam, int iRange, bool bIncrement, InvisibleTypes eSeeInvisible)
{
CvPlot* pLoopPlot;
CvPlot* pAdjacentPlot;
int iLevel;
int iDX, iDY;
int iI;
if (iRange == 0)
{
changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
return;
}
for (iDX = -(iRange - 1); iDX <= (iRange - 1); iDX++)
{
for (iDY = -(iRange - 1); iDY <= (iRange - 1); iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
if (pLoopPlot != NULL)
{
pLoopPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
iLevel = pLoopPlot->seeFromLevel(eTeam);
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
pAdjacentPlot->changeVisibilityCount(eTeam, ((bIncrement) ? 1 : -1), eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, ((DirectionTypes)iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnLeftDirection(iI), iLevel, bIncrement, eSeeInvisible);
pAdjacentPlot->changeSeeFromSight(eTeam, GC.getTurnRightDirection(iI), iLevel, bIncrement, eSeeInvisible);
}
}
}
}
}
}
void CvPlot::updateSight(bool bIncrement)
{
CLLNode<IDInfo>* pUnitNode;
CvCity* pCity;
CvCity* pHolyCity;
CvUnit* pLoopUnit;
int iLoop;
int iI;
pCity = getPlotCity();
if (pCity != NULL)
{
for (iI = 0; iI < GC.getNumReligionInfos(); iI++)
{
if (pCity->isHasReligion((ReligionTypes)iI))
{
pHolyCity = GC.getGameINLINE().getHolyCity((ReligionTypes)iI);
if (pHolyCity != NULL)
{
if (GET_PLAYER(pHolyCity->getOwnerINLINE()).getStateReligion() == iI)
{
changeAdjacentSight(pHolyCity->getTeam(), GC.getDefineINT("PLOT_VISIBILITY_RANGE"), bIncrement, NO_INVISIBLE);
}
}
}
}
}
if (isOwned())
{
changeAdjacentSight(getTeam(), GC.getDefineINT("PLOT_VISIBILITY_RANGE"), bIncrement, NO_INVISIBLE);
}
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
changeAdjacentSight(pLoopUnit->getTeam(), pLoopUnit->visibilityRange(), bIncrement, pLoopUnit->getSeeInvisibleType());
}
if (getReconCount() > 0)
{
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
for(pLoopUnit = GET_PLAYER((PlayerTypes)iI).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER((PlayerTypes)iI).nextUnit(&iLoop))
{
if (pLoopUnit->getReconPlot() == this)
{
changeAdjacentSight(pLoopUnit->getTeam(), pLoopUnit->getReconRange(), bIncrement, pLoopUnit->getSeeInvisibleType());
}
}
}
}
}
void CvPlot::updateSeeFromSight(bool bIncrement)
{
CvPlot* pLoopPlot;
int iDX, iDY;
for (iDX = -2; iDX <= 2; iDX++)
{
for (iDY = -2; iDY <= 2; iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
if (pLoopPlot != NULL)
{
pLoopPlot->updateSight(bIncrement);
}
}
}
}
bool CvPlot::canHaveBonus(BonusTypes eBonus, bool bIgnoreLatitude) const
{
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
if (eBonus == NO_BONUS)
{
return true;
}
if (getBonusType() != NO_BONUS)
{
return false;
}
if (isPeak())
{
return false;
}
if (getFeatureType() != NO_FEATURE)
{
if (!(GC.getBonusInfo(eBonus).isFeature(getFeatureType())))
{
return false;
}
if (!(GC.getBonusInfo(eBonus).isFeatureTerrain(getTerrainType())))
{
return false;
}
}
else
{
if (!(GC.getBonusInfo(eBonus).isTerrain(getTerrainType())))
{
return false;
}
}
if (isHills())
{
if (!(GC.getBonusInfo(eBonus).isHills()))
{
return false;
}
}
else if (isFlatlands())
{
if (!(GC.getBonusInfo(eBonus).isFlatlands()))
{
return false;
}
}
if (GC.getBonusInfo(eBonus).isNoRiverSide())
{
if (isRiverSide())
{
return false;
}
}
if (GC.getBonusInfo(eBonus).getMinAreaSize() != -1)
{
if (area()->getNumTiles() < GC.getBonusInfo(eBonus).getMinAreaSize())
{
return false;
}
}
if (!bIgnoreLatitude)
{
if (getLatitude() > GC.getBonusInfo(eBonus).getMaxLatitude())
{
return false;
}
if (getLatitude() < GC.getBonusInfo(eBonus).getMinLatitude())
{
return false;
}
}
if (!isPotentialCityWork())
{
return false;
}
return true;
}
bool CvPlot::canHaveImprovement(ImprovementTypes eImprovement, TeamTypes eTeam, bool bPotential) const
{
CvPlot* pLoopPlot;
bool bValid;
int iI;
FAssertMsg(eImprovement != NO_IMPROVEMENT, "Improvement is not assigned a valid value");
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
bValid = false;
if (isCity())
{
return false;
}
if (isImpassable())
{
return false;
}
if (GC.getImprovementInfo(eImprovement).isWater() != isWater())
{
return false;
}
if (getFeatureType() != NO_FEATURE)
{
if (GC.getFeatureInfo(getFeatureType()).isNoImprovement())
{
return false;
}
}
if ((getBonusType(eTeam) != NO_BONUS) && GC.getImprovementInfo(eImprovement).isImprovementBonusMakesValid(getBonusType(eTeam)))
{
return true;
}
if (GC.getImprovementInfo(eImprovement).isNoFreshWater() && isFreshWater())
{
return false;
}
if (GC.getImprovementInfo(eImprovement).isRequiresFlatlands() && !isFlatlands())
{
return false;
}
if (GC.getImprovementInfo(eImprovement).isRequiresFeature() && (getFeatureType() == NO_FEATURE))
{
return false;
}
if (GC.getImprovementInfo(eImprovement).isHillsMakesValid() && isHills())
{
bValid = true;
}
if (GC.getImprovementInfo(eImprovement).isFreshWaterMakesValid() && isFreshWater())
{
bValid = true;
}
if (GC.getImprovementInfo(eImprovement).isRiverSideMakesValid() && isRiverSide())
{
bValid = true;
}
if (GC.getImprovementInfo(eImprovement).getTerrainMakesValid(getTerrainType()))
{
bValid = true;
}
if ((getFeatureType() != NO_FEATURE) && GC.getImprovementInfo(eImprovement).getFeatureMakesValid(getFeatureType()))
{
bValid = true;
}
if (!bValid)
{
return false;
}
if (GC.getImprovementInfo(eImprovement).isRequiresRiverSide())
{
bValid = false;
for (iI = 0; iI < NUM_CARDINALDIRECTION_TYPES; iI++)
{
pLoopPlot = plotCardinalDirection(getX_INLINE(), getY_INLINE(), ((CardinalDirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (isRiverCrossing(directionXY(this, pLoopPlot)))
{
if (pLoopPlot->getImprovementType() != eImprovement)
{
bValid = true;
break;
}
}
}
}
if (!bValid)
{
return false;
}
}
for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
if (calculateNatureYield(((YieldTypes)iI), eTeam) < GC.getImprovementInfo(eImprovement).getPrereqNatureYield(iI))
{
return false;
}
}
if ((getTeam() == NO_TEAM) || !(GET_TEAM(getTeam()).isIgnoreIrrigation()))
{
if (!bPotential && GC.getImprovementInfo(eImprovement).isRequiresIrrigation() && !isIrrigationAvailable())
{
return false;
}
}
return true;
}
bool CvPlot::canBuild(BuildTypes eBuild, PlayerTypes ePlayer, bool bTestVisible) const
{
PROFILE_FUNC();
ImprovementTypes eImprovement;
ImprovementTypes eFinalImprovementType;
RouteTypes eRoute;
bool bValid;
if (eBuild == NO_BUILD)
{
return false;
}
bValid = false;
eImprovement = ((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement()));
if (eImprovement != NO_IMPROVEMENT)
{
if (!canHaveImprovement(eImprovement, GET_PLAYER(ePlayer).getTeam(), bTestVisible))
{
return false;
}
if (getImprovementType() != NO_IMPROVEMENT)
{
if (GC.getImprovementInfo(getImprovementType()).isPermanent())
{
return false;
}
if (getImprovementType() == eImprovement)
{
return false;
}
eFinalImprovementType = finalImprovementUpgrade(getImprovementType());
if (eFinalImprovementType != NO_IMPROVEMENT)
{
if (eFinalImprovementType == finalImprovementUpgrade(eImprovement))
{
return false;
}
}
}
if (!bTestVisible)
{
if (GET_PLAYER(ePlayer).getTeam() != getTeam())
{
return false;
}
}
bValid = true;
}
eRoute = ((RouteTypes)(GC.getBuildInfo(eBuild).getRoute()));
if (eRoute != NO_ROUTE)
{
if (getRouteType() != NO_ROUTE)
{
if (GC.getRouteInfo(getRouteType()).getValue() >= GC.getRouteInfo(eRoute).getValue())
{
return false;
}
}
if (!bTestVisible)
{
if (GC.getRouteInfo(eRoute).getPrereqBonus() != NO_BONUS)
{
if (!isAdjacentPlotGroupConnectedBonus(ePlayer, ((BonusTypes)(GC.getRouteInfo(eRoute).getPrereqBonus()))))
{
return false;
}
}
}
bValid = true;
}
if (getFeatureType() != NO_FEATURE)
{
if (GC.getBuildInfo(eBuild).isFeatureRemove(getFeatureType()))
{
if (isOwned() && (GET_PLAYER(ePlayer).getTeam() != getTeam()) && !atWar(GET_PLAYER(ePlayer).getTeam(), getTeam()))
{
return false;
}
bValid = true;
}
}
return bValid;
}
int CvPlot::getBuildTime(BuildTypes eBuild) const
{
int iTime;
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
iTime = GC.getBuildInfo(eBuild).getTime();
if (getFeatureType() != NO_FEATURE)
{
iTime += GC.getBuildInfo(eBuild).getFeatureTime(getFeatureType());
}
iTime *= max(0, (GC.getTerrainInfo(getTerrainType()).getBuildModifier() + 100));
iTime /= 100;
iTime *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getBuildPercent();
iTime /= 100;
iTime *= GC.getEraInfo(GC.getGameINLINE().getStartEra()).getBuildPercent();
iTime /= 100;
return iTime;
}
int CvPlot::getBuildTurnsLeft(BuildTypes eBuild, int iNowExtra, int iThenExtra) const
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
int iNowBuildRate;
int iThenBuildRate;
int iBuildLeft;
int iTurnsLeft;
iNowBuildRate = iNowExtra;
iThenBuildRate = iThenExtra;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if (pLoopUnit->getBuildType() == eBuild)
{
if (pLoopUnit->canMove())
{
iNowBuildRate += pLoopUnit->workRate(false);
}
iThenBuildRate += pLoopUnit->workRate(true);
}
}
if (iThenBuildRate == 0)
{
return MAX_INT;
}
iBuildLeft = getBuildTime(eBuild);
iBuildLeft -= getBuildProgress(eBuild);
iBuildLeft -= iNowBuildRate;
iBuildLeft = max(0, iBuildLeft);
iTurnsLeft = (iBuildLeft / iThenBuildRate);
if ((iTurnsLeft * iThenBuildRate) < iBuildLeft)
{
iTurnsLeft++;
}
iTurnsLeft++;
return max(1, iTurnsLeft);
}
int CvPlot::getFeatureProduction(BuildTypes eBuild, TeamTypes eTeam, CvCity** ppCity) const
{
int iProduction;
if (getFeatureType() == NO_FEATURE)
{
return 0;
}
*ppCity = getWorkingCity();
if (*ppCity == NULL)
{
*ppCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), NO_PLAYER, eTeam, false);
}
if (*ppCity == NULL)
{
return 0;
}
iProduction = (GC.getBuildInfo(eBuild).getFeatureProduction(getFeatureType()) - (max(0, (plotDistance(getX_INLINE(), getY_INLINE(), (*ppCity)->getX_INLINE(), (*ppCity)->getY_INLINE()) - 2)) * 5));
iProduction = (*ppCity)->getExtraProductionDifference(iProduction);
iProduction *= max(0, (GET_PLAYER((*ppCity)->getOwnerINLINE()).getFeatureProductionModifier() + 100));
iProduction /= 100;
iProduction *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getFeatureProductionPercent();
iProduction /= 100;
iProduction *= min((GC.getDefineINT("BASE_FEATURE_PRODUCTION_PERCENT") + (GC.getDefineINT("FEATURE_PRODUCTION_PERCENT_MULTIPLIER") * (*ppCity)->getPopulation())), 100);
iProduction /= 100;
if (getTeam() != eTeam)
{
iProduction *= GC.getDefineINT("DIFFERENT_TEAM_FEATURE_PRODUCTION_PERCENT");
iProduction /= 100;
}
return max(0, iProduction);
}
CvUnit* CvPlot::getBestDefender(PlayerTypes eOwner, PlayerTypes eAttackingPlayer, const CvUnit* pAttacker, bool bTestAtWar, bool bTestPotentialEnemy, bool bTestCanMove) const
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
CvUnit* pBestUnit;
pBestUnit = NULL;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if ((eOwner == NO_PLAYER) || (pLoopUnit->getOwnerINLINE() == eOwner))
{
if ((eAttackingPlayer == NO_PLAYER) || !(pLoopUnit->isInvisible(GET_PLAYER(eAttackingPlayer).getTeam(), false)))
{
if (!bTestAtWar || (eAttackingPlayer == NO_PLAYER) || atWar(GET_PLAYER(eAttackingPlayer).getTeam(), pLoopUnit->getTeam()))
{
if (!bTestPotentialEnemy || (eAttackingPlayer == NO_PLAYER) || isPotentialEnemy(GET_PLAYER(eAttackingPlayer).getTeam(), pLoopUnit->getTeam()))
{
if (!bTestCanMove || (pLoopUnit->canMove() && !(pLoopUnit->isCargo())))
{
if ((pAttacker == NULL) || (pAttacker->getDomainType() != DOMAIN_AIR) || (pLoopUnit->getDamage() < pAttacker->airCombatLimit()))
{
if (pLoopUnit->isBetterDefenderThan(pBestUnit, pAttacker))
{
pBestUnit = pLoopUnit;
}
}
}
}
}
}
}
}
return pBestUnit;
}
CvUnit* CvPlot::getSelectedUnit() const
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if (pLoopUnit->IsSelected())
{
return pLoopUnit;
}
}
return NULL;
}
int CvPlot::getUnitPower(PlayerTypes eOwner) const
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
int iCount;
iCount = 0;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if ((eOwner == NO_PLAYER) || (pLoopUnit->getOwnerINLINE() == eOwner))
{
iCount += GC.getUnitInfo(pLoopUnit->getUnitType()).getPowerValue();
}
}
return iCount;
}
int CvPlot::defenseModifier(bool bIgnoreBuilding, bool bHelp) const
{
CvCity* pCity;
ImprovementTypes eImprovement;
int iModifier;
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
iModifier = ((getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(getTerrainType()).getDefenseModifier() : GC.getFeatureInfo(getFeatureType()).getDefenseModifier());
if (isHills())
{
iModifier += GC.getHILLS_EXTRA_DEFENSE();
}
if (bHelp)
{
eImprovement = getRevealedImprovementType(GC.getGameINLINE().getActiveTeam(), false);
}
else
{
eImprovement = getImprovementType();
}
if (eImprovement != NO_IMPROVEMENT)
{
iModifier += GC.getImprovementInfo(eImprovement).getDefenseModifier();
}
if (!bHelp)
{
pCity = getPlotCity();
if (pCity != NULL)
{
iModifier += pCity->getDefenseModifier(bIgnoreBuilding);
}
}
return iModifier;
}
int CvPlot::movementCost(const CvUnit* pUnit, const CvPlot* pFromPlot) const
{
PROFILE_FUNC();
int iRegularCost;
int iRouteCost;
int iRouteFlatCost;
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
if (pUnit->flatMovementCost() || (pUnit->getDomainType() == DOMAIN_AIR))
{
return GC.getMOVE_DENOMINATOR();
}
if (pUnit->isHuman())
{
if (!isRevealed(pUnit->getTeam(), false))
{
return pUnit->maxMoves();
}
}
if (!(pFromPlot->isValidDomainForLocation(pUnit->getDomainType())))
{
return pUnit->maxMoves();
}
if (!isValidDomainForAction(pUnit->getDomainType()))
{
return GC.getMOVE_DENOMINATOR();
}
FAssert(pUnit->getDomainType() != DOMAIN_IMMOBILE);
if (pUnit->ignoreTerrainCost())
{
iRegularCost = 1;
}
else
{
iRegularCost = ((getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(getTerrainType()).getMovementCost() : GC.getFeatureInfo(getFeatureType()).getMovementCost());
if (isHills())
{
iRegularCost += GC.getHILLS_EXTRA_MOVEMENT();
}
if (iRegularCost > 0)
{
iRegularCost = max(1, (iRegularCost - pUnit->getExtraMoveDiscount()));
}
}
iRegularCost = min(iRegularCost, pUnit->baseMoves());
iRegularCost *= GC.getMOVE_DENOMINATOR();
if (((getFeatureType() == NO_FEATURE) ? pUnit->isTerrainDoubleMove(getTerrainType()) : pUnit->isFeatureDoubleMove(getFeatureType())) ||
(isHills() && pUnit->isHillsDoubleMove()))
{
iRegularCost /= 2;
}
if (pFromPlot->isValidRoute(pUnit) && isValidRoute(pUnit) && ((GET_TEAM(pUnit->getTeam()).isBridgeBuilding() || !(pFromPlot->isRiverCrossing(directionXY(pFromPlot, this))))))
{
iRouteCost = max((GC.getRouteInfo(pFromPlot->getRouteType()).getMovementCost() + GET_TEAM(pUnit->getTeam()).getRouteChange(pFromPlot->getRouteType())),
(GC.getRouteInfo(getRouteType()).getMovementCost() + GET_TEAM(pUnit->getTeam()).getRouteChange(getRouteType())));
iRouteFlatCost = max((GC.getRouteInfo(pFromPlot->getRouteType()).getFlatMovementCost() * pUnit->baseMoves()),
(GC.getRouteInfo(getRouteType()).getFlatMovementCost() * pUnit->baseMoves()));
}
else
{
iRouteCost = MAX_INT;
iRouteFlatCost = MAX_INT;
}
return max(1, min(iRegularCost, min(iRouteCost, iRouteFlatCost)));
}
bool CvPlot::isAdjacentOwned() const
{
CvPlot* pAdjacentPlot;
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->isOwned())
{
return true;
}
}
}
return false;
}
bool CvPlot::isAdjacentPlayer(PlayerTypes ePlayer, bool bLandOnly) const
{
CvPlot* pAdjacentPlot;
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->getOwnerINLINE() == ePlayer)
{
if (!bLandOnly || !(pAdjacentPlot->isWater()))
{
return true;
}
}
}
}
return false;
}
bool CvPlot::isAdjacentTeam(TeamTypes eTeam, bool bLandOnly) const
{
CvPlot* pAdjacentPlot;
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->getTeam() == eTeam)
{
if (!bLandOnly || !(pAdjacentPlot->isWater()))
{
return true;
}
}
}
}
return false;
}
bool CvPlot::isWithinCultureRange(PlayerTypes ePlayer) const
{
int iI;
for (iI = 0; iI < GC.getNumCultureLevelInfos(); iI++)
{
if (isCultureRangeCity(ePlayer, iI))
{
return true;
}
}
return false;
}
int CvPlot::getNumCultureRangeCities(PlayerTypes ePlayer) const
{
int iCount;
int iI;
iCount = 0;
for (iI = 0; iI < GC.getNumCultureLevelInfos(); iI++)
{
iCount += getCultureRangeCities(ePlayer, iI);
}
return iCount;
}
PlayerTypes CvPlot::calculateCulturalOwner() const
{
PROFILE("CvPlot::calculateCulturalOwner()")
CvCity* pLoopCity;
CvCity* pBestCity;
CvPlot* pLoopPlot;
PlayerTypes eBestPlayer;
bool bValid;
int iCulture;
int iBestCulture;
int iPriority;
int iBestPriority;
int iI;
if (isForceUnowned())
{
return NO_PLAYER;
}
iBestCulture = 0;
eBestPlayer = NO_PLAYER;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
iCulture = getCulture((PlayerTypes)iI);
if (iCulture > 0)
{
if (isWithinCultureRange((PlayerTypes)iI))
{
if ((iCulture > iBestCulture) || ((iCulture == iBestCulture) && (getOwnerINLINE() == iI)))
{
iBestCulture = iCulture;
eBestPlayer = ((PlayerTypes)iI);
}
}
}
}
}
if (!isCity())
{
if (eBestPlayer != NO_PLAYER)
{
iBestPriority = MAX_INT;
pBestCity = NULL;
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
pLoopCity = pLoopPlot->getPlotCity();
if (pLoopCity != NULL)
{
if (pLoopCity->getTeam() == GET_PLAYER(eBestPlayer).getTeam())
{
if (getCulture(pLoopCity->getOwnerINLINE()) > 0)
{
if (isWithinCultureRange(pLoopCity->getOwnerINLINE()))
{
iPriority = GC.getCityPlotPriority()[iI];
if ((iPriority < iBestPriority) || ((iPriority == iBestPriority) && (pLoopCity->getOwnerINLINE() == eBestPlayer)))
{
iBestPriority = iPriority;
pBestCity = pLoopCity;
}
}
}
}
}
}
}
if (pBestCity != NULL)
{
eBestPlayer = pBestCity->getOwnerINLINE();
}
}
}
if (eBestPlayer == NO_PLAYER)
{
bValid = true;
for (iI = 0; iI < NUM_CARDINALDIRECTION_TYPES; iI++)
{
pLoopPlot = plotCardinalDirection(getX_INLINE(), getY_INLINE(), ((CardinalDirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (pLoopPlot->isOwned())
{
if (eBestPlayer == NO_PLAYER)
{
eBestPlayer = pLoopPlot->getOwnerINLINE();
}
else if (eBestPlayer != pLoopPlot->getOwnerINLINE())
{
bValid = false;
break;
}
}
else
{
bValid = false;
break;
}
}
}
if (!bValid)
{
eBestPlayer = NO_PLAYER;
}
}
return eBestPlayer;
}
void CvPlot::plotAction(PlotUnitFunc func, int iData1, int iData2, PlayerTypes eOwner, TeamTypes eTeam)
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if ((eOwner == NO_PLAYER) || (pLoopUnit->getOwnerINLINE() == eOwner))
{
if ((eTeam == NO_TEAM) || (pLoopUnit->getTeam() == eTeam))
{
func(pLoopUnit, iData1, iData2);
}
}
}
}
int CvPlot::plotCount(ConstPlotUnitFunc funcA, int iData1A, int iData2A, PlayerTypes eOwner, TeamTypes eTeam, ConstPlotUnitFunc funcB, int iData1B, int iData2B) const
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
int iCount;
iCount = 0;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if ((eOwner == NO_PLAYER) || (pLoopUnit->getOwnerINLINE() == eOwner))
{
if ((eTeam == NO_TEAM) || (pLoopUnit->getTeam() == eTeam))
{
if ((funcA == NULL) || funcA(pLoopUnit, iData1A, iData2A))
{
if ((funcB == NULL) || funcB(pLoopUnit, iData1B, iData2B))
{
iCount++;
}
}
}
}
}
return iCount;
}
CvUnit* CvPlot::plotCheck(ConstPlotUnitFunc funcA, int iData1A, int iData2A, PlayerTypes eOwner, TeamTypes eTeam, ConstPlotUnitFunc funcB, int iData1B, int iData2B) const
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if ((eOwner == NO_PLAYER) || (pLoopUnit->getOwnerINLINE() == eOwner))
{
if ((eTeam == NO_TEAM) || (pLoopUnit->getTeam() == eTeam))
{
if (funcA(pLoopUnit, iData1A, iData2A))
{
if ((funcB == NULL) || funcB(pLoopUnit, iData1B, iData2B))
{
return pLoopUnit;
}
}
}
}
}
return NULL;
}
bool CvPlot::isOwned() const
{
return (getOwnerINLINE() != NO_PLAYER);
}
bool CvPlot::isBarbarian() const
{
return (getOwnerINLINE() == BARBARIAN_PLAYER);
}
bool CvPlot::isRevealedBarbarian() const
{
return (getRevealedOwner(GC.getGameINLINE().getActiveTeam(), true) == BARBARIAN_PLAYER);
}
bool CvPlot::isVisible(TeamTypes eTeam, bool bDebug) const
{
if (bDebug && GC.getGameINLINE().isDebugMode())
{
return true;
}
else
{
if (eTeam == NO_TEAM)
{
return false;
}
return ((getVisibilityCount(eTeam) > 0) || (getStolenVisibilityCount(eTeam) > 0));
}
}
bool CvPlot::isActiveVisible(bool bDebug) const
{
return isVisible(GC.getGameINLINE().getActiveTeam(), bDebug);
}
bool CvPlot::isVisibleToCivTeam() const
{
int iI;
for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
{
if (GET_TEAM((TeamTypes)iI).isAlive())
{
if (isVisible(((TeamTypes)iI), false))
{
return true;
}
}
}
return false;
}
bool CvPlot::isVisibleToWatchingHuman() const
{
int iI;
for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
if (GET_PLAYER((PlayerTypes)iI).isHuman())
{
if (isVisible(GET_PLAYER((PlayerTypes)iI).getTeam(), false))
{
return true;
}
}
}
}
return false;
}
bool CvPlot::isAdjacentVisible(TeamTypes eTeam, bool bDebug) const
{
CvPlot* pAdjacentPlot;
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->isVisible(eTeam, bDebug))
{
return true;
}
}
}
return false;
}
bool CvPlot::isGoody(TeamTypes eTeam) const
{
if ((eTeam != NO_TEAM) && GET_TEAM(eTeam).isBarbarian())
{
return false;
}
return ((getImprovementType() == NO_IMPROVEMENT) ? false : GC.getImprovementInfo(getImprovementType()).isGoody());
}
bool CvPlot::isRevealedGoody(TeamTypes eTeam) const
{
if (eTeam == NO_TEAM)
{
return isGoody();
}
if (GET_TEAM(eTeam).isBarbarian())
{
return false;
}
return ((getRevealedImprovementType(eTeam, false) == NO_IMPROVEMENT) ? false : GC.getImprovementInfo(getRevealedImprovementType(eTeam, false)).isGoody());
}
void CvPlot::removeGoody()
{
setImprovementType(NO_IMPROVEMENT);
}
bool CvPlot::isCity() const
{
return (getPlotCity() != NULL);
}
bool CvPlot::isFriendlyCity(TeamTypes eTeam) const
{
CvCity* pCity;
pCity = getPlotCity();
if (pCity != NULL)
{
return ((pCity->getTeam() == eTeam) || GET_TEAM(eTeam).isOpenBorders(pCity->getTeam()));
}
return false;
}
bool CvPlot::isEnemyCity(TeamTypes eTeam) const
{
CvCity* pCity;
pCity = getPlotCity();
if (pCity != NULL)
{
return atWar(pCity->getTeam(), eTeam);
}
return false;
}
bool CvPlot::isOccupation() const
{
CvCity* pCity;
pCity = getPlotCity();
if (pCity != NULL)
{
return pCity->isOccupation();
}
return false;
}
bool CvPlot::isBeingWorked() const
{
CvCity* pWorkingCity;
pWorkingCity = getWorkingCity();
if (pWorkingCity != NULL)
{
return pWorkingCity->isWorkingPlot(this);
}
return false;
}
bool CvPlot::isUnit() const
{
return (getNumUnits() > 0);
}
bool CvPlot::isInvestigate(TeamTypes eTeam) const
{
return (plotCheck(PUF_isInvestigate, -1, -1, NO_PLAYER, eTeam) != NULL);
}
bool CvPlot::isVisibleEnemyDefender(PlayerTypes ePlayer) const
{
return (plotCheck(PUF_canDefendEnemy, ePlayer, -1, NO_PLAYER, NO_TEAM, PUF_isVisible, ePlayer) != NULL);
}
CvUnit *CvPlot::getVisibleEnemyDefender(PlayerTypes ePlayer) const
{
return plotCheck(PUF_canDefendEnemy, ePlayer, -1, NO_PLAYER, NO_TEAM, PUF_isVisible, ePlayer);
}
int CvPlot::getNumDefenders(PlayerTypes ePlayer) const
{
return plotCount(PUF_canDefend, -1, -1, ePlayer);
}
int CvPlot::getNumVisibleEnemyDefenders(PlayerTypes ePlayer) const
{
return plotCount(PUF_canDefendEnemy, ePlayer, -1, NO_PLAYER, NO_TEAM, PUF_isVisible, ePlayer);
}
int CvPlot::getNumVisiblePotentialEnemyDefenders(PlayerTypes ePlayer) const
{
return plotCount(PUF_canDefendPotentialEnemy, ePlayer, -1, NO_PLAYER, NO_TEAM, PUF_isVisible, ePlayer);
}
bool CvPlot::isVisibleEnemyUnit(PlayerTypes ePlayer) const
{
return (plotCheck(PUF_isEnemy, ePlayer, -1, NO_PLAYER, NO_TEAM, PUF_isVisible, ePlayer) != NULL);
}
bool CvPlot::isVisibleOtherUnit(PlayerTypes ePlayer) const
{
return (plotCheck(PUF_isOtherTeam, ePlayer, -1, NO_PLAYER, NO_TEAM, PUF_isVisible, ePlayer) != NULL);
}
bool CvPlot::isFighting() const
{
return (plotCheck(PUF_isFighting) != NULL);
}
bool CvPlot::canHaveFeature(FeatureTypes eFeature) const
{
CvPlot* pAdjacentPlot;
int iI;
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
if (eFeature == NO_FEATURE)
{
return true;
}
if (getFeatureType() != NO_FEATURE)
{
return false;
}
if (isPeak())
{
return false;
}
if (isCity())
{
return false;
}
if (!(GC.getFeatureInfo(eFeature).isTerrain(getTerrainType())))
{
return false;
}
if (GC.getFeatureInfo(eFeature).isNoCoast() && isCoastalLand())
{
return false;
}
if (GC.getFeatureInfo(eFeature).isNoRiver() && isRiver())
{
return false;
}
if (GC.getFeatureInfo(eFeature).isRequiresFlatlands() && isHills())
{
return false;
}
if (GC.getFeatureInfo(eFeature).isNoAdjacent())
{
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->getFeatureType() == eFeature)
{
return false;
}
}
}
}
if (GC.getFeatureInfo(eFeature).isRequiresRiver() && !isRiver())
{
return false;
}
return true;
}
bool CvPlot::isRoute() const
{
return (getRouteType() != NO_ROUTE);
}
bool CvPlot::isValidRoute(const CvUnit* pUnit) const
{
if (isRoute())
{
if (!atWar(pUnit->getTeam(), getTeam()) || pUnit->isEnemyRoute())
{
return true;
}
}
return false;
}
bool CvPlot::isTradeNetworkImpassable() const
{
return (isImpassable() && !isRiver());
}
bool CvPlot::isNetworkTerrain(TeamTypes eTeam) const
{
FAssertMsg(eTeam != NO_TEAM, "eTeam is not assigned a valid value");
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
if (GET_TEAM(eTeam).isTerrainTrade(getTerrainType()))
{
return true;
}
if (isWater())
{
if (isOwned())
{
return true;
}
}
return false;
}
bool CvPlot::isBonusNetwork(TeamTypes eTeam) const
{
return (isRoute() || isRiver() || isNetworkTerrain(eTeam));
}
bool CvPlot::isTradeNetwork(TeamTypes eTeam) const
{
FAssertMsg(eTeam != NO_TEAM, "eTeam is not assigned a valid value");
if (atWar(eTeam, getTeam()))
{
return false;
}
if (isTradeNetworkImpassable())
{
return false;
}
if (!isOwned())
{
if (!isRevealed(eTeam, false))
{
return false;
}
}
return isBonusNetwork(eTeam);
}
bool CvPlot::isTradeNetworkConnected(const CvPlot* pPlot, TeamTypes eTeam) const
{
FAssertMsg(eTeam != NO_TEAM, "eTeam is not assigned a valid value");
if (atWar(eTeam, getTeam()) || atWar(eTeam, pPlot->getTeam()))
{
return false;
}
if (isTradeNetworkImpassable() || pPlot->isTradeNetworkImpassable())
{
return false;
}
if (!isOwned())
{
if (!isRevealed(eTeam, false) || !(pPlot->isRevealed(eTeam, false)))
{
return false;
}
}
if (isRoute())
{
if (pPlot->isRoute())
{
return true;
}
}
if (isCity())
{
if (pPlot->isNetworkTerrain(eTeam))
{
return true;
}
}
if (isNetworkTerrain(eTeam))
{
if (pPlot->isCity())
{
return true;
}
if (pPlot->isNetworkTerrain(eTeam))
{
return true;
}
if (pPlot->isRiver())
{
if (pPlot->isRiverConnection(directionXY(pPlot, this)))
{
return true;
}
}
}
if (isRiver())
{
if (pPlot->isNetworkTerrain(eTeam))
{
if (isRiverConnection(directionXY(this, pPlot)))
{
return true;
}
}
if (isRiverConnection(directionXY(this, pPlot)) || pPlot->isRiverConnection(directionXY(pPlot, this)))
{
if (pPlot->isRiver())
{
return true;
}
}
}
return false;
}
bool CvPlot::isValidDomainForLocation(DomainTypes eDomain) const
{
if (isValidDomainForAction(eDomain))
{
return true;
}
return isCity();
}
bool CvPlot::isValidDomainForAction(DomainTypes eDomain) const
{
switch (eDomain)
{
case DOMAIN_SEA:
return isWater();
break;
case DOMAIN_AIR:
return false;
break;
case DOMAIN_LAND:
case DOMAIN_IMMOBILE:
return !(isWater());
break;
default:
FAssert(false);
break;
}
return false;
}
bool CvPlot::isImpassable() const
{
if (isPeak())
{
return true;
}
if (getTerrainType() == NO_TERRAIN)
{
return false;
}
return ((getFeatureType() == NO_FEATURE) ? GC.getTerrainInfo(getTerrainType()).isImpassable() : GC.getFeatureInfo(getFeatureType()).isImpassable());
}
int CvPlot::getX() const
{
return m_iX;
}
int CvPlot::getY() const
{
return m_iY;
}
bool CvPlot::at(int iX, int iY) const
{
return ((getX_INLINE() == iX) && (getY_INLINE() == iY));
}
int CvPlot::getLatitude() const
{
int iLatitude;
if (GC.getMapINLINE().isWrapXINLINE() || !(GC.getMapINLINE().isWrapYINLINE()))
{
iLatitude = ((getY_INLINE() * 100) / GC.getMapINLINE().getGridHeightINLINE());
}
else
{
iLatitude = ((getX_INLINE() * 100) / GC.getMapINLINE().getGridWidthINLINE());
}
iLatitude = ((iLatitude * (GC.getMapINLINE().getTopLatitude() - GC.getMapINLINE().getBottomLatitude())) / 100);
return abs(iLatitude + GC.getMapINLINE().getBottomLatitude());
}
int CvPlot::getFOWIndex() const
{
return ((((gDLL->getEngineIFace()->GetNumGameCellsY() - 1) - getY_INLINE()) * gDLL->getEngineIFace()->GetNumGameCellsX() * LANDSCAPE_FOW_RESOLUTION*LANDSCAPE_FOW_RESOLUTION) + (getX_INLINE() * LANDSCAPE_FOW_RESOLUTION));
}
CvArea* CvPlot::area() const
{
return GC.getMapINLINE().getArea(getArea());
}
CvArea* CvPlot::waterArea() const
{
CvArea* pBestArea;
CvPlot* pAdjacentPlot;
int iValue;
int iBestValue;
int iI;
if (isWater())
{
return area();
}
iBestValue = 0;
pBestArea = NULL;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->isWater())
{
iValue = pAdjacentPlot->area()->getNumTiles();
if (iValue > iBestValue)
{
iBestValue = iValue;
pBestArea = pAdjacentPlot->area();
}
}
}
}
return pBestArea;
}
int CvPlot::getArea() const
{
return m_iArea;
}
void CvPlot::setArea(int iNewValue)
{
bool bOldLake;
if (getArea() != iNewValue)
{
bOldLake = isLake();
if (area() != NULL)
{
processArea(area(), -1);
}
m_iArea = iNewValue;
if (area() != NULL)
{
processArea(area(), 1);
updateIrrigated();
updateYield();
}
}
}
int CvPlot::getFeatureVariety() const
{
FAssert((getFeatureType() == NO_FEATURE) || (m_iFeatureVariety < GC.getFeatureInfo(getFeatureType()).getNumVarieties()));
FAssert(m_iFeatureVariety >= 0);
return m_iFeatureVariety;
}
int CvPlot::getOwnershipDuration() const
{
return m_iOwnershipDuration;
}
bool CvPlot::isOwnershipScore() const
{
return (getOwnershipDuration() >= GC.getDefineINT("OWNERSHIP_SCORE_DURATION_THRESHOLD"));
}
void CvPlot::setOwnershipDuration(int iNewValue)
{
bool bOldOwnershipScore;
if (getOwnershipDuration() != iNewValue)
{
bOldOwnershipScore = isOwnershipScore();
m_iOwnershipDuration = iNewValue;
FAssert(getOwnershipDuration() >= 0);
if (bOldOwnershipScore != isOwnershipScore())
{
if (isOwned())
{
if (!isWater())
{
GET_PLAYER(getOwnerINLINE()).changeTotalLandScored((isOwnershipScore()) ? 1 : -1);
}
}
}
}
}
void CvPlot::changeOwnershipDuration(int iChange)
{
setOwnershipDuration(getOwnershipDuration() + iChange);
}
int CvPlot::getImprovementDuration() const
{
return m_iImprovementDuration;
}
void CvPlot::setImprovementDuration(int iNewValue)
{
m_iImprovementDuration = iNewValue;
FAssert(getImprovementDuration() >= 0);
}
void CvPlot::changeImprovementDuration(int iChange)
{
setImprovementDuration(getImprovementDuration() + iChange);
}
int CvPlot::getUpgradeProgress() const
{
return m_iUpgradeProgress;
}
int CvPlot::getUpgradeTimeLeft(ImprovementTypes eImprovement, PlayerTypes ePlayer) const
{
int iUpgradeLeft;
int iUpgradeRate;
int iTurnsLeft;
iUpgradeLeft = (GC.getGameINLINE().getImprovementUpgradeTime(eImprovement) - ((getImprovementType() == eImprovement) ? getUpgradeProgress() : 0));
if (ePlayer == NO_PLAYER)
{
return iUpgradeLeft;
}
iUpgradeRate = GET_PLAYER(ePlayer).getImprovementUpgradeRate();
if (iUpgradeRate == 0)
{
return iUpgradeLeft;
}
iTurnsLeft = (iUpgradeLeft / iUpgradeRate);
if ((iTurnsLeft * iUpgradeRate) < iUpgradeLeft)
{
iTurnsLeft++;
}
return max(1, iTurnsLeft);
}
void CvPlot::setUpgradeProgress(int iNewValue)
{
m_iUpgradeProgress = iNewValue;
FAssert(getUpgradeProgress() >= 0);
}
void CvPlot::changeUpgradeProgress(int iChange)
{
setUpgradeProgress(getUpgradeProgress() + iChange);
}
int CvPlot::getForceUnownedTimer() const
{
return m_iForceUnownedTimer;
}
bool CvPlot::isForceUnowned() const
{
return (getForceUnownedTimer() > 0);
}
void CvPlot::setForceUnownedTimer(int iNewValue)
{
m_iForceUnownedTimer = iNewValue;
FAssert(getForceUnownedTimer() >= 0);
}
void CvPlot::changeForceUnownedTimer(int iChange)
{
setForceUnownedTimer(getForceUnownedTimer() + iChange);
}
int CvPlot::getCityRadiusCount() const
{
return m_iCityRadiusCount;
}
int CvPlot::isCityRadius() const
{
return (getCityRadiusCount() > 0);
}
void CvPlot::changeCityRadiusCount(int iChange)
{
m_iCityRadiusCount = (m_iCityRadiusCount + iChange);
FAssert(getCityRadiusCount() >= 0);
}
bool CvPlot::isStartingPlot() const
{
return m_bStartingPlot;
}
void CvPlot::setStartingPlot(bool bNewValue)
{
m_bStartingPlot = bNewValue;
}
bool CvPlot::isNOfRiver() const
{
return m_bNOfRiver;
}
void CvPlot::setNOfRiver(bool bNewValue, CardinalDirectionTypes eRiverDir)
{
CvPlot* pAdjacentPlot;
int iI;
if ((isNOfRiver() != bNewValue) || (eRiverDir != m_eRiverWEDirection))
{
if (isNOfRiver() != bNewValue)
{
updatePlotGroupBonus(false);
m_bNOfRiver = bNewValue;
updatePlotGroupBonus(true);
updateRiverCrossing();
updateYield();
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
pAdjacentPlot->updateRiverCrossing();
pAdjacentPlot->updateYield();
}
}
if (area() != NULL)
{
area()->changeNumRiverEdges((isNOfRiver()) ? 1 : -1);
}
}
FAssertMsg(eRiverDir == CARDINALDIRECTION_WEST || eRiverDir == CARDINALDIRECTION_EAST || eRiverDir == NO_CARDINALDIRECTION, "invalid parameter");
m_eRiverWEDirection = eRiverDir;
updateRiverSymbol(true, true);
}
}
bool CvPlot::isWOfRiver() const
{
return m_bWOfRiver;
}
void CvPlot::setWOfRiver(bool bNewValue, CardinalDirectionTypes eRiverDir)
{
CvPlot* pAdjacentPlot;
int iI;
if ((isWOfRiver() != bNewValue) || (eRiverDir != m_eRiverNSDirection))
{
if (isWOfRiver() != bNewValue)
{
updatePlotGroupBonus(false);
m_bWOfRiver = bNewValue;
updatePlotGroupBonus(true);
updateRiverCrossing();
updateYield();
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
pAdjacentPlot->updateRiverCrossing();
pAdjacentPlot->updateYield();
}
}
if (area())
{
area()->changeNumRiverEdges((isWOfRiver()) ? 1 : -1);
}
}
FAssertMsg(eRiverDir == CARDINALDIRECTION_NORTH || eRiverDir == CARDINALDIRECTION_SOUTH || eRiverDir == NO_CARDINALDIRECTION, "invalid parameter");
m_eRiverNSDirection = eRiverDir;
updateRiverSymbol(true, true);
}
}
CardinalDirectionTypes CvPlot::getRiverNSDirection() const
{
return (CardinalDirectionTypes)m_eRiverNSDirection;
}
CardinalDirectionTypes CvPlot::getRiverWEDirection() const
{
return (CardinalDirectionTypes)m_eRiverWEDirection;
}
// This function finds an *inland* corner of this plot at which to place a river.
// It then returns the plot with that corner at its SE.
CvPlot* CvPlot::getInlandCorner() const
{
CvPlot* pRiverPlot = NULL; // will be a plot through whose SE corner we want the river to run
int aiShuffle[4];
shuffleArray(aiShuffle, 4, GC.getGameINLINE().getMapRand());
for (int iI = 0; iI < 4; iI++)
{
switch (aiShuffle[iI])
{
case 0:
pRiverPlot = GC.getMapINLINE().plotSorenINLINE(getX_INLINE(), getY_INLINE()); break;
case 1:
pRiverPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTH); break;
case 2:
pRiverPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTHWEST); break;
case 3:
pRiverPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_WEST); break;
}
if (pRiverPlot != NULL && !pRiverPlot->hasCoastAtSECorner())
{
break;
}
else
{
pRiverPlot = NULL;
}
}
return pRiverPlot;
}
bool CvPlot::hasCoastAtSECorner() const
{
CvPlot* pAdjacentPlot;
if (isWater())
{
return true;
}
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_EAST);
if (pAdjacentPlot != NULL && pAdjacentPlot->isWater())
{
return true;
}
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_SOUTHEAST);
if (pAdjacentPlot != NULL && pAdjacentPlot->isWater())
{
return true;
}
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_SOUTH);
if (pAdjacentPlot != NULL && pAdjacentPlot->isWater())
{
return true;
}
return false;
}
bool CvPlot::isIrrigated() const
{
return m_bIrrigated;
}
void CvPlot::setIrrigated(bool bNewValue)
{
CvPlot* pLoopPlot;
int iDX, iDY;
if (isIrrigated() != bNewValue)
{
m_bIrrigated = bNewValue;
for (iDX = -1; iDX <= 1; iDX++)
{
for (iDY = -1; iDY <= 1; iDY++)
{
pLoopPlot = plotXY(getX_INLINE(), getY_INLINE(), iDX, iDY);
if (pLoopPlot != NULL)
{
pLoopPlot->updateYield();
pLoopPlot->setLayoutDirty(true);
}
}
}
}
}
void CvPlot::updateIrrigated()
{
PROFILE("CvPlot::updateIrrigated()");
CvPlot* pLoopPlot;
FAStar* pIrrigatedFinder;
bool bFoundFreshWater;
bool bIrrigated;
int iI;
if (area() == NULL)
{
return;
}
if (!(GC.getGameINLINE().isFinalInitialized()))
{
return;
}
pIrrigatedFinder = gDLL->getFAStarIFace()->create();
if (isIrrigated())
{
if (!isPotentialIrrigation())
{
setIrrigated(false);
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pLoopPlot != NULL)
{
bFoundFreshWater = false;
gDLL->getFAStarIFace()->Initialize(pIrrigatedFinder, GC.getMapINLINE().getGridWidthINLINE(), GC.getMapINLINE().getGridHeightINLINE(), GC.getMapINLINE().isWrapXINLINE(), GC.getMapINLINE().isWrapYINLINE(), NULL, NULL, NULL, potentialIrrigation, NULL, checkFreshWater, &bFoundFreshWater);
gDLL->getFAStarIFace()->GeneratePath(pIrrigatedFinder, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), -1, -1);
if (!bFoundFreshWater)
{
bIrrigated = false;
gDLL->getFAStarIFace()->Initialize(pIrrigatedFinder, GC.getMapINLINE().getGridWidthINLINE(), GC.getMapINLINE().getGridHeightINLINE(), GC.getMapINLINE().isWrapXINLINE(), GC.getMapINLINE().isWrapYINLINE(), NULL, NULL, NULL, potentialIrrigation, NULL, changeIrrigated, &bIrrigated);
gDLL->getFAStarIFace()->GeneratePath(pIrrigatedFinder, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), -1, -1);
}
}
}
}
}
else
{
if (isPotentialIrrigation() && isIrrigationAvailable(true))
{
bIrrigated = true;
gDLL->getFAStarIFace()->Initialize(pIrrigatedFinder, GC.getMapINLINE().getGridWidthINLINE(), GC.getMapINLINE().getGridHeightINLINE(), GC.getMapINLINE().isWrapXINLINE(), GC.getMapINLINE().isWrapYINLINE(), NULL, NULL, NULL, potentialIrrigation, NULL, changeIrrigated, &bIrrigated);
gDLL->getFAStarIFace()->GeneratePath(pIrrigatedFinder, getX_INLINE(), getY_INLINE(), -1, -1);
}
}
gDLL->getFAStarIFace()->destroy(pIrrigatedFinder);
}
bool CvPlot::isPotentialCityWork() const
{
return m_bPotentialCityWork;
}
bool CvPlot::isPotentialCityWorkForArea(CvArea* pArea) const
{
PROFILE_FUNC();
CvPlot* pLoopPlot;
int iI;
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
if (!(pLoopPlot->isWater()))
{
if (pLoopPlot->area() == pArea)
{
return true;
}
}
}
}
return false;
}
void CvPlot::updatePotentialCityWork()
{
PROFILE_FUNC();
CvPlot* pLoopPlot;
bool bValid;
int iI;
bValid = false;
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
if (!(pLoopPlot->isWater()))
{
bValid = true;
break;
}
}
}
if (isPotentialCityWork() != bValid)
{
m_bPotentialCityWork = bValid;
updateYield();
}
}
bool CvPlot::isShowCitySymbols() const
{
return m_bShowCitySymbols;
}
void CvPlot::updateShowCitySymbols()
{
CvCity* pLoopCity;
CvPlot* pLoopPlot;
bool bNewShowCitySymbols;
int iI;
bNewShowCitySymbols = false;
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
pLoopCity = pLoopPlot->getPlotCity();
if (pLoopCity != NULL)
{
if (pLoopCity->isCitySelected())
{
if (pLoopCity->canWork(this))
{
bNewShowCitySymbols = true;
break;
}
}
}
}
}
if (isShowCitySymbols() != bNewShowCitySymbols)
{
m_bShowCitySymbols = bNewShowCitySymbols;
updateSymbolDisplay();
updateSymbolVisibility();
}
}
bool CvPlot::isFlagDirty() const
{
return m_bFlagDirty;
}
void CvPlot::setFlagDirty(bool bNewValue)
{
m_bFlagDirty = bNewValue;
}
PlayerTypes CvPlot::getOwner() const
{
return getOwnerINLINE();
}
void CvPlot::setOwner(PlayerTypes eNewValue)
{
PROFILE_FUNC();
CLLNode<IDInfo>* pUnitNode;
CvCity* pOldCity;
CvCity* pNewCity;
CvUnit* pLoopUnit;
CvWString szBuffer;
UnitTypes eBestUnit;
int iFreeUnits;
int iI;
if (getOwnerINLINE() != eNewValue)
{
GC.getGameINLINE().addReplayMessage(REPLAY_MESSAGE_PLOT_OWNER_CHANGE, eNewValue, (char*)NULL, getX_INLINE(), getY_INLINE());
pOldCity = getPlotCity();
if (pOldCity != NULL)
{
szBuffer = gDLL->getText("TXT_KEY_MISC_CITY_REVOLTED_JOINED", pOldCity->getNameKey(), GET_PLAYER(eNewValue).getCivilizationDescriptionKey());
gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_CULTUREFLIP", MESSAGE_TYPE_MAJOR_EVENT, ARTFILEMGR.getInterfaceArtInfo("WORLDBUILDER_CITY_EDIT")->getPath(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
gDLL->getInterfaceIFace()->addMessage(eNewValue, false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_CULTUREFLIP", MESSAGE_TYPE_MAJOR_EVENT, ARTFILEMGR.getInterfaceArtInfo("WORLDBUILDER_CITY_EDIT")->getPath(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
szBuffer = gDLL->getText("TXT_KEY_MISC_CITY_REVOLTS_JOINS", pOldCity->getNameKey(), GET_PLAYER(eNewValue).getCivilizationDescriptionKey());
GC.getGameINLINE().addReplayMessage(REPLAY_MESSAGE_MAJOR_EVENT, getOwnerINLINE(), szBuffer, getX_INLINE(), getY_INLINE(), (ColorTypes)GC.getInfoTypeForString("COLOR_ALT_HIGHLIGHT_TEXT"));
FAssertMsg(pOldCity->getOwnerINLINE() != eNewValue, "pOldCity->getOwnerINLINE() is not expected to be equal with eNewValue");
GET_PLAYER(eNewValue).acquireCity(pOldCity, false, false); // will delete the pointer
pOldCity = NULL;
pNewCity = getPlotCity();
FAssertMsg(pNewCity != NULL, "NewCity is not assigned a valid value");
if (pNewCity != NULL)
{
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if (atWar(pLoopUnit->getTeam(), GET_PLAYER(eNewValue).getTeam()))
{
FAssert(pLoopUnit->getTeam() != GET_PLAYER(eNewValue).getTeam());
pLoopUnit->kill(false, eNewValue);
}
}
eBestUnit = pNewCity->AI_bestUnitAI(UNITAI_CITY_DEFENSE);
if (eBestUnit == NO_UNIT)
{
eBestUnit = pNewCity->AI_bestUnitAI(UNITAI_ATTACK);
}
if (eBestUnit != NO_UNIT)
{
iFreeUnits = (GC.getDefineINT("BASE_REVOLT_FREE_UNITS") + ((pNewCity->getHighestPopulation() * GC.getDefineINT("REVOLT_FREE_UNITS_PERCENT")) / 100));
for (iI = 0; iI < iFreeUnits; iI++)
{
GET_PLAYER(eNewValue).initUnit(eBestUnit, getX_INLINE(), getY_INLINE(), UNITAI_CITY_DEFENSE);
}
}
}
}
else
{
setOwnershipDuration(0);
if (isOwned())
{
changeAdjacentSight(getTeam(), GC.getDefineINT("PLOT_VISIBILITY_RANGE"), false, NO_INVISIBLE);
if (area())
{
area()->changeNumOwnedTiles(-1);
}
GC.getMapINLINE().changeOwnedPlots(-1);
if (!isWater())
{
GET_PLAYER(getOwnerINLINE()).changeTotalLand(-1);
GET_TEAM(getTeam()).changeTotalLand(-1);
if (isOwnershipScore())
{
GET_PLAYER(getOwnerINLINE()).changeTotalLandScored(-1);
}
}
if (getImprovementType() != NO_IMPROVEMENT)
{
GET_PLAYER(getOwnerINLINE()).changeImprovementCount(getImprovementType(), -1);
}
updatePlotGroupBonus(false);
}
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if (pLoopUnit->getTeam() != getTeam())
{
GET_PLAYER(pLoopUnit->getOwnerINLINE()).changeNumOutsideUnits(-1);
}
}
m_eOwner = eNewValue;
setWorkingCityOverride(NULL);
updateWorkingCity();
if (isOwned())
{
changeAdjacentSight(getTeam(), GC.getDefineINT("PLOT_VISIBILITY_RANGE"), true, NO_INVISIBLE);
if (area())
{
area()->changeNumOwnedTiles(1);
}
GC.getMapINLINE().changeOwnedPlots(1);
if (!isWater())
{
GET_PLAYER(getOwnerINLINE()).changeTotalLand(1);
GET_TEAM(getTeam()).changeTotalLand(1);
if (isOwnershipScore())
{
GET_PLAYER(getOwnerINLINE()).changeTotalLandScored(1);
}
}
if (getImprovementType() != NO_IMPROVEMENT)
{
GET_PLAYER(getOwnerINLINE()).changeImprovementCount(getImprovementType(), 1);
}
updatePlotGroupBonus(true);
}
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if (pLoopUnit->getTeam() != getTeam())
{
GET_PLAYER(pLoopUnit->getOwnerINLINE()).changeNumOutsideUnits(1);
}
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (GET_TEAM((TeamTypes)iI).isAlive())
{
updateRevealedOwner((TeamTypes)iI);
}
}
updateIrrigated();
updateYield();
updatePlotGroup();
verifyUnitValidPlot();
if (isOwned())
{
if (isGoody())
{
GET_PLAYER(getOwnerINLINE()).doGoody(this, NULL);
}
for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
{
if (GET_TEAM((TeamTypes)iI).isAlive())
{
if (isVisible((TeamTypes)iI, false))
{
GET_TEAM((TeamTypes)iI).meet(getTeam(), true);
}
}
}
}
if (GC.getGameINLINE().isDebugMode())
{
updateMinimapColor();
gDLL->getInterfaceIFace()->setDirty(GlobeLayer_DIRTY_BIT, true);
gDLL->getEngineIFace()->SetDirty(CultureBorders_DIRTY_BIT, true);
}
}
}
}
PlotTypes CvPlot::getPlotType() const
{
return (PlotTypes)m_ePlotType;
}
bool CvPlot::isWater() const
{
return (getPlotType() == PLOT_OCEAN);
}
bool CvPlot::isFlatlands() const
{
return (getPlotType() == PLOT_LAND);
}
bool CvPlot::isHills() const
{
return (getPlotType() == PLOT_HILLS);
}
bool CvPlot::isPeak() const
{
return (getPlotType() == PLOT_PEAK);
}
void CvPlot::setPlotType(PlotTypes eNewValue, bool bRecalculate, bool bRebuildGraphics)
{
CvArea* pNewArea;
CvArea* pCurrArea;
CvArea* pLastArea;
CvPlot* pLoopPlot;
bool bWasWater;
bool bRecalculateAreas;
int iAreaCount;
int iI;
if (getPlotType() != eNewValue)
{
if ((getPlotType() == PLOT_OCEAN) || (eNewValue == PLOT_OCEAN))
{
erase();
}
bWasWater = isWater();
updateSeeFromSight(false);
m_ePlotType = eNewValue;
updateYield();
updatePlotGroup();
updateSeeFromSight(true);
if ((getTerrainType() == NO_TERRAIN) || (GC.getTerrainInfo(getTerrainType()).isWater() != isWater()))
{
if (isWater())
{
if (isAdjacentToLand())
{
setTerrainType(((TerrainTypes)(GC.getDefineINT("SHALLOW_WATER_TERRAIN"))), bRecalculate, bRebuildGraphics);
}
else
{
setTerrainType(((TerrainTypes)(GC.getDefineINT("DEEP_WATER_TERRAIN"))), bRecalculate, bRebuildGraphics);
}
}
else
{
setTerrainType(((TerrainTypes)(GC.getDefineINT("LAND_TERRAIN"))), bRecalculate, bRebuildGraphics);
}
}
GC.getMapINLINE().resetPathDistance();
if (bWasWater != isWater())
{
if (bRecalculate)
{
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (pLoopPlot->isWater())
{
if (pLoopPlot->isAdjacentToLand())
{
pLoopPlot->setTerrainType(((TerrainTypes)(GC.getDefineINT("SHALLOW_WATER_TERRAIN"))), bRecalculate, bRebuildGraphics);
}
else
{
pLoopPlot->setTerrainType(((TerrainTypes)(GC.getDefineINT("DEEP_WATER_TERRAIN"))), bRecalculate, bRebuildGraphics);
}
}
}
}
}
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pLoopPlot != NULL)
{
pLoopPlot->updateYield();
pLoopPlot->updatePlotGroup();
}
}
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
pLoopPlot->updatePotentialCityWork();
}
}
GC.getMapINLINE().changeLandPlots((isWater()) ? -1 : 1);
if (getBonusType() != NO_BONUS)
{
GC.getMapINLINE().changeNumBonusesOnLand(getBonusType(), ((isWater()) ? -1 : 1));
}
if (isOwned())
{
GET_PLAYER(getOwnerINLINE()).changeTotalLand((isWater()) ? -1 : 1);
GET_TEAM(getTeam()).changeTotalLand((isWater()) ? -1 : 1);
}
if (bRecalculate)
{
pNewArea = NULL;
bRecalculateAreas = false;
// XXX might want to change this if we allow diagonal water movement...
if (isWater())
{
for (iI = 0; iI < NUM_CARDINALDIRECTION_TYPES; iI++)
{
pLoopPlot = plotCardinalDirection(getX_INLINE(), getY_INLINE(), ((CardinalDirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (pLoopPlot->area()->isWater())
{
if (pNewArea == NULL)
{
pNewArea = pLoopPlot->area();
}
else if (pNewArea != pLoopPlot->area())
{
bRecalculateAreas = true;
break;
}
}
}
}
}
else
{
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pLoopPlot != NULL)
{
if (!(pLoopPlot->area()->isWater()))
{
if (pNewArea == NULL)
{
pNewArea = pLoopPlot->area();
}
else if (pNewArea != pLoopPlot->area())
{
bRecalculateAreas = true;
break;
}
}
}
}
}
if (!bRecalculateAreas)
{
pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)(NUM_DIRECTION_TYPES - 1)));
if (pLoopPlot != NULL)
{
pLastArea = pLoopPlot->area();
}
else
{
pLastArea = NULL;
}
iAreaCount = 0;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pLoopPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pLoopPlot != NULL)
{
pCurrArea = pLoopPlot->area();
}
else
{
pCurrArea = NULL;
}
if (pCurrArea != pLastArea)
{
iAreaCount++;
}
pLastArea = pCurrArea;
}
if (iAreaCount > 2)
{
bRecalculateAreas = true;
}
}
if (bRecalculateAreas)
{
GC.getMapINLINE().recalculateAreas();
}
else
{
setArea(FFreeList::INVALID_INDEX);
if ((area() != NULL) && (area()->getNumTiles() == 1))
{
GC.getMapINLINE().deleteArea(getArea());
}
if (pNewArea == NULL)
{
pNewArea = GC.getMapINLINE().addArea();
pNewArea->init(pNewArea->getID(), isWater());
}
setArea(pNewArea->getID());
}
}
}
if (bRebuildGraphics && GC.IsGraphicsInitialized())
{
//Update terrain graphical
gDLL->getEngineIFace()->RebuildPlot(getX_INLINE(), getY_INLINE(), true, true);
//gDLL->getEngineIFace()->SetDirty(MinimapTexture_DIRTY_BIT, true); //minimap does a partial update
//gDLL->getEngineIFace()->SetDirty(GlobeTexture_DIRTY_BIT, true);
updateFeatureSymbol();
setLayoutDirty(true);
updateRouteSymbol(false, true);
updateRiverSymbol(false, true);
}
}
}
TerrainTypes CvPlot::getTerrainType() const
{
return (TerrainTypes)m_eTerrainType;
}
void CvPlot::setTerrainType(TerrainTypes eNewValue, bool bRecalculate, bool bRebuildGraphics)
{
bool bUpdateSight;
if (getTerrainType() != eNewValue)
{
if ((getTerrainType() != NO_TERRAIN) &&
(eNewValue != NO_TERRAIN) &&
((GC.getTerrainInfo(getTerrainType()).getSeeFromLevel() != GC.getTerrainInfo(eNewValue).getSeeFromLevel()) ||
(GC.getTerrainInfo(getTerrainType()).getSeeThroughLevel() != GC.getTerrainInfo(eNewValue).getSeeThroughLevel())))
{
bUpdateSight = true;
}
else
{
bUpdateSight = false;
}
if (bUpdateSight)
{
updateSeeFromSight(false);
}
m_eTerrainType = eNewValue;
updateYield();
updatePlotGroup();
if (bUpdateSight)
{
updateSeeFromSight(true);
}
if (bRebuildGraphics && GC.IsGraphicsInitialized())
{
//Update terrain graphics
gDLL->getEngineIFace()->RebuildPlot(getX_INLINE(), getY_INLINE(),false,true);
//gDLL->getEngineIFace()->SetDirty(MinimapTexture_DIRTY_BIT, true); //minimap does a partial update
//gDLL->getEngineIFace()->SetDirty(GlobeTexture_DIRTY_BIT, true);
}
if (GC.getTerrainInfo(getTerrainType()).isWater() != isWater())
{
setPlotType(((GC.getTerrainInfo(getTerrainType()).isWater()) ? PLOT_OCEAN : PLOT_LAND), bRecalculate, bRebuildGraphics);
}
}
}
FeatureTypes CvPlot::getFeatureType() const
{
return (FeatureTypes)m_eFeatureType;
}
void CvPlot::setFeatureType(FeatureTypes eNewValue, int iVariety)
{
CvCity* pLoopCity;
CvPlot* pLoopPlot;
FeatureTypes eOldFeature;
bool bUpdateSight;
int iI;
eOldFeature = getFeatureType();
if (eOldFeature != eNewValue)
{
if ((eOldFeature == NO_FEATURE) ||
(eNewValue == NO_FEATURE) ||
(GC.getFeatureInfo(eOldFeature).getSeeThroughChange() != GC.getFeatureInfo(eNewValue).getSeeThroughChange()))
{
bUpdateSight = true;
}
else
{
bUpdateSight = false;
}
if (bUpdateSight)
{
updateSeeFromSight(false);
}
m_eFeatureType = eNewValue;
if (getFeatureType() != NO_FEATURE)
{
if (iVariety == -1)
{
iVariety = ((GC.getFeatureInfo(getFeatureType()).getNumVarieties() * ((getLatitude() * 9) / 8)) / 90);
}
m_iFeatureVariety = range(iVariety, 0, (GC.getFeatureInfo(getFeatureType()).getNumVarieties() - 1));
}
else
{
m_iFeatureVariety = 0;
}
updateYield();
if (bUpdateSight)
{
updateSeeFromSight(true);
}
updateFeatureSymbol();
if (((eOldFeature != NO_FEATURE) && (GC.getFeatureInfo(eOldFeature).getArtInfo()->isRiverArt())) ||
((getFeatureType() != NO_FEATURE) && (GC.getFeatureInfo(getFeatureType()).getArtInfo()->isRiverArt())))
{
updateRiverSymbolArt(true);
}
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
pLoopCity = pLoopPlot->getPlotCity();
if (pLoopCity != NULL)
{
pLoopCity->updateFeatureHealth();
pLoopCity->updateFeatureHappiness();
}
}
}
if (getFeatureType() == NO_FEATURE)
{
if (getImprovementType() != NO_IMPROVEMENT)
{
if (GC.getImprovementInfo(getImprovementType()).isRequiresFeature())
{
setImprovementType(NO_IMPROVEMENT);
}
}
}
}
}
BonusTypes CvPlot::getBonusType(TeamTypes eTeam) const
{
if (eTeam != NO_TEAM)
{
if (m_eBonusType != NO_BONUS)
{
if (!(GET_TEAM(eTeam).isHasTech((TechTypes)(GC.getBonusInfo((BonusTypes)m_eBonusType).getTechReveal()))))
{
return NO_BONUS;
}
}
}
return (BonusTypes)m_eBonusType;
}
BonusTypes CvPlot::getNonObsoleteBonusType(TeamTypes eTeam) const
{
BonusTypes eBonus;
FAssert(eTeam != NO_TEAM);
eBonus = getBonusType(eTeam);
if (eBonus != NO_BONUS)
{
if ((GC.getBonusInfo(eBonus).getTechObsolete() != NO_TECH) && GET_TEAM(eTeam).isHasTech((TechTypes)(GC.getBonusInfo(eBonus).getTechObsolete())))
{
return NO_BONUS;
}
}
return eBonus;
}
void CvPlot::setBonusType(BonusTypes eNewValue)
{
if (getBonusType() != eNewValue)
{
if (getBonusType() != NO_BONUS)
{
if (area())
{
area()->changeNumBonuses(getBonusType(), -1);
}
GC.getMapINLINE().changeNumBonuses(getBonusType(), -1);
if (!isWater())
{
GC.getMapINLINE().changeNumBonusesOnLand(getBonusType(), -1);
}
}
updatePlotGroupBonus(false);
m_eBonusType = eNewValue;
updatePlotGroupBonus(true);
if (getBonusType() != NO_BONUS)
{
if (area())
{
area()->changeNumBonuses(getBonusType(), 1);
}
GC.getMapINLINE().changeNumBonuses(getBonusType(), 1);
if (!isWater())
{
GC.getMapINLINE().changeNumBonusesOnLand(getBonusType(), 1);
}
}
updateYield();
setLayoutDirty(true);
gDLL->getInterfaceIFace()->setDirty(GlobeLayer_DIRTY_BIT, true);
}
}
ImprovementTypes CvPlot::getImprovementType() const
{
return (ImprovementTypes)m_eImprovementType;
}
void CvPlot::setImprovementType(ImprovementTypes eNewValue)
{
int iI;
if (getImprovementType() != eNewValue)
{
if (getImprovementType() != NO_IMPROVEMENT)
{
if (area())
{
area()->changeNumImprovements(getImprovementType(), -1);
}
if (isOwned())
{
GET_PLAYER(getOwnerINLINE()).changeImprovementCount(getImprovementType(), -1);
}
}
updatePlotGroupBonus(false);
m_eImprovementType = eNewValue;
updatePlotGroupBonus(true);
if (getImprovementType() == NO_IMPROVEMENT)
{
setImprovementDuration(0);
}
setUpgradeProgress(0);
for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (GET_TEAM((TeamTypes)iI).isAlive())
{
if (isVisible((TeamTypes)iI, false))
{
setRevealedImprovementType((TeamTypes)iI, getImprovementType());
}
}
}
if (getImprovementType() != NO_IMPROVEMENT)
{
if (area())
{
area()->changeNumImprovements(getImprovementType(), 1);
}
if (isOwned())
{
GET_PLAYER(getOwnerINLINE()).changeImprovementCount(getImprovementType(), 1);
}
}
updateIrrigated();
updateYield();
if (GC.getGameINLINE().isDebugMode())
{
setLayoutDirty(true);
}
if (getImprovementType() != NO_IMPROVEMENT)
{
gDLL->getEventReporterIFace()->improvementBuilt(getImprovementType(), getX_INLINE(), getY_INLINE());
}
}
}
RouteTypes CvPlot::getRouteType() const
{
return (RouteTypes)m_eRouteType;
}
void CvPlot::setRouteType(RouteTypes eNewValue)
{
bool bOldRoute;
int iI;
if (getRouteType() != eNewValue)
{
bOldRoute = isRoute(); // XXX is this right???
updatePlotGroupBonus(false);
m_eRouteType = eNewValue;
updatePlotGroupBonus(true);
for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (GET_TEAM((TeamTypes)iI).isAlive())
{
if (isVisible((TeamTypes)iI, false))
{
setRevealedRouteType((TeamTypes)iI, getRouteType());
}
}
}
updateYield();
if (bOldRoute != isRoute())
{
updatePlotGroup();
}
if (GC.getGameINLINE().isDebugMode())
{
updateRouteSymbol(true, true);
}
if (getRouteType() != NO_ROUTE)
{
gDLL->getEventReporterIFace()->routeBuilt(getRouteType(), getX_INLINE(), getY_INLINE());
}
}
}
void CvPlot::updateCityRoute()
{
RouteTypes eCityRoute;
if (isCity())
{
FAssertMsg(isOwned(), "isOwned is expected to be true");
eCityRoute = GET_PLAYER(getOwnerINLINE()).getBestRoute();
if (eCityRoute == NO_ROUTE)
{
eCityRoute = ((RouteTypes)(GC.getDefineINT("INITIAL_CITY_ROUTE_TYPE")));
}
setRouteType(eCityRoute);
}
}
CvCity* CvPlot::getPlotCity() const
{
return getCity(m_plotCity);
}
void CvPlot::setPlotCity(CvCity* pNewValue)
{
CvPlotGroup* pPlotGroup;
CvPlot* pLoopPlot;
int iI;
if (getPlotCity() != pNewValue)
{
if (isCity())
{
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
pLoopPlot->changeCityRadiusCount(-1);
pLoopPlot->changePlayerCityRadiusCount(getPlotCity()->getOwnerINLINE(), -1);
}
}
}
updatePlotGroupBonus(false);
if (isCity())
{
pPlotGroup = getPlotGroup(getOwnerINLINE());
if (pPlotGroup != NULL)
{
FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlot::setPlotCity");
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
getPlotCity()->changeNumBonuses(((BonusTypes)iI), -(pPlotGroup->getNumBonuses((BonusTypes)iI)));
}
}
}
if (pNewValue != NULL)
{
m_plotCity = pNewValue->getIDInfo();
}
else
{
m_plotCity.reset();
}
if (isCity())
{
pPlotGroup = getPlotGroup(getOwnerINLINE());
if (pPlotGroup != NULL)
{
FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlot::setPlotCity");
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
getPlotCity()->changeNumBonuses(((BonusTypes)iI), pPlotGroup->getNumBonuses((BonusTypes)iI));
}
}
}
updatePlotGroupBonus(true);
if (isCity())
{
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
pLoopPlot->changeCityRadiusCount(1);
pLoopPlot->changePlayerCityRadiusCount(getPlotCity()->getOwnerINLINE(), 1);
}
}
}
updateIrrigated();
updateYield();
updatePlotGroup();
updateMinimapColor();
}
}
CvCity* CvPlot::getWorkingCity() const
{
return getCity(m_workingCity);
}
void CvPlot::updateWorkingCity()
{
CvCity* pOldWorkingCity;
CvCity* pLoopCity;
CvCity* pBestCity;
CvPlot* pLoopPlot;
int iBestPlot;
int iI;
pBestCity = getPlotCity();
if (pBestCity == NULL)
{
pBestCity = getWorkingCityOverride();
FAssertMsg((pBestCity == NULL) || (pBestCity->getOwnerINLINE() == getOwnerINLINE()), "pBest city is expected to either be NULL or the current plot instance's");
}
if ((pBestCity == NULL) && isOwned())
{
iBestPlot = 0;
for (iI = 0; iI < NUM_CITY_PLOTS; iI++)
{
pLoopPlot = plotCity(getX_INLINE(), getY_INLINE(), iI);
if (pLoopPlot != NULL)
{
pLoopCity = pLoopPlot->getPlotCity();
if (pLoopCity != NULL)
{
if (pLoopCity->getOwnerINLINE() == getOwnerINLINE())
{
// XXX use getGameTurnAcquired() instead???
if ((pBestCity == NULL) ||
(GC.getCityPlotPriority()[iI] < GC.getCityPlotPriority()[iBestPlot]) ||
((GC.getCityPlotPriority()[iI] == GC.getCityPlotPriority()[iBestPlot]) &&
((pLoopCity->getGameTurnFounded() < pBestCity->getGameTurnFounded()) ||
((pLoopCity->getGameTurnFounded() == pBestCity->getGameTurnFounded()) &&
(pLoopCity->getID() < pBestCity->getID())))))
{
iBestPlot = iI;
pBestCity = pLoopCity;
}
}
}
}
}
}
pOldWorkingCity = getWorkingCity();
if (pOldWorkingCity != pBestCity)
{
if (pOldWorkingCity != NULL)
{
pOldWorkingCity->setWorkingPlot(this, false);
}
if (pBestCity != NULL)
{
FAssertMsg(isOwned(), "isOwned is expected to be true");
FAssertMsg(!isBeingWorked(), "isBeingWorked did not return false as expected");
m_workingCity = pBestCity->getIDInfo();
}
else
{
m_workingCity.reset();
}
if (pOldWorkingCity != NULL)
{
pOldWorkingCity->AI_setAssignWorkDirty(true);
}
if (getWorkingCity() != NULL)
{
getWorkingCity()->AI_setAssignWorkDirty(true);
}
updateYield();
updateFog();
updateShowCitySymbols();
if (getOwnerINLINE() == GC.getGameINLINE().getActivePlayer())
{
if (gDLL->getGraphicOption(GRAPHICOPTION_CITY_RADIUS))
{
if (gDLL->getInterfaceIFace()->canSelectionListFound())
{
gDLL->getInterfaceIFace()->setDirty(ColoredPlots_DIRTY_BIT, true);
}
}
}
}
}
CvCity* CvPlot::getWorkingCityOverride() const
{
return getCity(m_workingCityOverride);
}
void CvPlot::setWorkingCityOverride( const CvCity* pNewValue)
{
if (getWorkingCityOverride() != pNewValue)
{
if (pNewValue != NULL)
{
FAssertMsg(pNewValue->getOwnerINLINE() == getOwnerINLINE(), "Argument city pNewValue's owner is expected to be the same as the current instance");
m_workingCityOverride = pNewValue->getIDInfo();
}
else
{
m_workingCityOverride.reset();
}
updateWorkingCity();
}
}
int CvPlot::getRiverID() const
{
return m_iRiverID;
}
void CvPlot::setRiverID(int iNewValue)
{
m_iRiverID = iNewValue;
}
int CvPlot::getMinOriginalStartDist() const
{
return m_iMinOriginalStartDist;
}
void CvPlot::setMinOriginalStartDist(int iNewValue)
{
m_iMinOriginalStartDist = iNewValue;
}
int CvPlot::getReconCount() const
{
return m_iReconCount;
}
void CvPlot::changeReconCount(int iChange)
{
m_iReconCount = (m_iReconCount + iChange);
FAssert(getReconCount() >= 0);
}
int CvPlot::getRiverCrossingCount() const
{
return m_iRiverCrossingCount;
}
void CvPlot::changeRiverCrossingCount(int iChange)
{
m_iRiverCrossingCount = (m_iRiverCrossingCount + iChange);
FAssert(getRiverCrossingCount() >= 0);
}
short* CvPlot::getYield()
{
return m_aiYield;
}
int CvPlot::getYield(YieldTypes eIndex) const
{
FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < NUM_YIELD_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
return m_aiYield[eIndex];
}
int CvPlot::calculateNatureYield(YieldTypes eYield, TeamTypes eTeam, bool bIgnoreFeature) const
{
PROFILE_FUNC();
BonusTypes eBonus;
int iYield;
if (isImpassable())
{
return 0;
}
FAssertMsg(getTerrainType() != NO_TERRAIN, "TerrainType is not assigned a valid value");
iYield = GC.getTerrainInfo(getTerrainType()).getYield(eYield);
if (isHills())
{
iYield += GC.getYieldInfo(eYield).getHillsChange();
}
if (isPeak())
{
iYield += GC.getYieldInfo(eYield).getPeakChange();
}
if (isLake())
{
iYield += GC.getYieldInfo(eYield).getLakeChange();
}
if (eTeam != NO_TEAM)
{
eBonus = getBonusType(eTeam);
if (eBonus != NO_BONUS)
{
iYield += GC.getBonusInfo(eBonus).getYieldChange(eYield);
}
}
if (isRiver())
{
iYield += ((bIgnoreFeature || (getFeatureType() == NO_FEATURE)) ? GC.getTerrainInfo(getTerrainType()).getRiverYieldChange(eYield) : GC.getFeatureInfo(getFeatureType()).getRiverYieldChange(eYield));
}
if (isHills())
{
iYield += ((bIgnoreFeature || (getFeatureType() == NO_FEATURE)) ? GC.getTerrainInfo(getTerrainType()).getHillsYieldChange(eYield) : GC.getFeatureInfo(getFeatureType()).getHillsYieldChange(eYield));
}
if (!bIgnoreFeature)
{
if (getFeatureType() != NO_FEATURE)
{
iYield += GC.getFeatureInfo(getFeatureType()).getYieldChange(eYield);
}
}
return max(0, iYield);
}
int CvPlot::calculateBestNatureYield(YieldTypes eIndex, TeamTypes eTeam) const
{
return max(calculateNatureYield(eIndex, eTeam, false), calculateNatureYield(eIndex, eTeam, true));
}
int CvPlot::calculateTotalBestNatureYield(TeamTypes eTeam) const
{
return (calculateBestNatureYield(YIELD_FOOD, eTeam) + calculateBestNatureYield(YIELD_PRODUCTION, eTeam) + calculateBestNatureYield(YIELD_COMMERCE, eTeam));
}
int CvPlot::calculateImprovementYieldChange(ImprovementTypes eImprovement, YieldTypes eYield, PlayerTypes ePlayer, bool bOptimal) const
{
PROFILE_FUNC();
BonusTypes eBonus;
int iBestYield;
int iYield;
int iI;
iYield = GC.getImprovementInfo(eImprovement).getYieldChange(eYield);
if (isRiverSide())
{
iYield += GC.getImprovementInfo(eImprovement).getRiverSideYieldChange(eYield);
}
if (isHills())
{
iYield += GC.getImprovementInfo(eImprovement).getHillsYieldChange(eYield);
}
if ((bOptimal) ? true : isIrrigationAvailable())
{
iYield += GC.getImprovementInfo(eImprovement).getIrrigatedYieldChange(eYield);
}
if (bOptimal)
{
iBestYield = 0;
for (iI = 0; iI < GC.getNumRouteInfos(); iI++)
{
iBestYield = max(iBestYield, GC.getImprovementInfo(eImprovement).getRouteYieldChanges(iI, eYield));
}
iYield += iBestYield;
}
else
{
if (getRouteType() != NO_ROUTE)
{
iYield += GC.getImprovementInfo(eImprovement).getRouteYieldChanges(getRouteType(), eYield);
}
}
if (bOptimal || ePlayer == NO_PLAYER)
{
for (iI = 0; iI < GC.getNumTechInfos(); iI++)
{
iYield += GC.getImprovementInfo(eImprovement).getTechYieldChanges(iI, eYield);
}
for (iI = 0; iI < GC.getNumCivicInfos(); iI++)
{
iYield += GC.getCivicInfo((CivicTypes) iI).getImprovementYieldChanges(eImprovement, eYield);
}
}
else
{
iYield += GET_PLAYER(ePlayer).getImprovementYieldChange(eImprovement, eYield);
iYield += GET_TEAM(GET_PLAYER(ePlayer).getTeam()).getImprovementYieldChange(eImprovement, eYield);
}
if (ePlayer != NO_PLAYER)
{
eBonus = getBonusType(GET_PLAYER(ePlayer).getTeam());
if (eBonus != NO_BONUS)
{
iYield += GC.getImprovementInfo(eImprovement).getImprovementBonusYield(eBonus, eYield);
}
}
return iYield;
}
int CvPlot::calculateYield(YieldTypes eYield, bool bDisplay) const
{
CvCity* pCity;
CvCity* pWorkingCity;
ImprovementTypes eImprovement;
RouteTypes eRoute;
PlayerTypes ePlayer;
bool bCity;
int iYield;
if (bDisplay && GC.getGameINLINE().isDebugMode())
{
return getYield(eYield);
}
if (getTerrainType() == NO_TERRAIN)
{
return 0;
}
if (!isPotentialCityWork())
{
return 0;
}
bCity = false;
if (bDisplay)
{
ePlayer = getRevealedOwner(GC.getGameINLINE().getActiveTeam(), false);
eImprovement = getRevealedImprovementType(GC.getGameINLINE().getActiveTeam(), false);
eRoute = getRevealedRouteType(GC.getGameINLINE().getActiveTeam(), false);
if (ePlayer == NO_PLAYER)
{
ePlayer = GC.getGameINLINE().getActivePlayer();
}
}
else
{
ePlayer = getOwnerINLINE();
eImprovement = getImprovementType();
eRoute = getRouteType();
}
iYield = calculateNatureYield(eYield, ((ePlayer != NO_PLAYER) ? GET_PLAYER(ePlayer).getTeam() : NO_TEAM));
if (eImprovement != NO_IMPROVEMENT)
{
iYield += calculateImprovementYieldChange(eImprovement, eYield, ePlayer);
}
if (eRoute != NO_ROUTE)
{
iYield += GC.getRouteInfo(eRoute).getYieldChange(eYield);
}
if (ePlayer != NO_PLAYER)
{
pCity = getPlotCity();
if (pCity != NULL)
{
if (!bDisplay || pCity->isRevealed(GC.getGameINLINE().getActiveTeam(), false))
{
iYield += GC.getYieldInfo(eYield).getCityChange();
if (GC.getYieldInfo(eYield).getPopulationChangeDivisor() != 0)
{
iYield += ((pCity->getPopulation() + GC.getYieldInfo(eYield).getPopulationChangeOffset()) / GC.getYieldInfo(eYield).getPopulationChangeDivisor());
}
bCity = true;
}
}
if (isWater())
{
if (!isImpassable())
{
iYield += GET_PLAYER(ePlayer).getSeaPlotYield(eYield);
pWorkingCity = getWorkingCity();
if (pWorkingCity != NULL)
{
if (!bDisplay || pWorkingCity->isRevealed(GC.getGameINLINE().getActiveTeam(), false))
{
iYield += pWorkingCity->getSeaPlotYield(eYield);
}
}
}
}
}
if (bCity)
{
iYield = max(iYield, GC.getYieldInfo(eYield).getMinCity());
}
if (ePlayer != NO_PLAYER)
{
if (GET_PLAYER(ePlayer).getExtraYieldThreshold(eYield) > 0)
{
if (iYield >= GET_PLAYER(ePlayer).getExtraYieldThreshold(eYield))
{
iYield += GC.getDefineINT("EXTRA_YIELD");
}
}
if (GET_PLAYER(ePlayer).isGoldenAge())
{
if (iYield >= GC.getYieldInfo(eYield).getGoldenAgeYieldThreshold())
{
iYield += GC.getYieldInfo(eYield).getGoldenAgeYield();
}
}
}
return max(0, iYield);
}
bool CvPlot::hasYield() const
{
int iI;
for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
if (getYield((YieldTypes)iI) > 0)
{
return true;
}
}
return false;
}
void CvPlot::updateYield()
{
CvCity* pWorkingCity;
bool bChange;
int iNewYield;
int iOldYield;
int iI;
if (area() == NULL)
{
return;
}
bChange = false;
for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
{
iNewYield = calculateYield((YieldTypes)iI);
if (getYield((YieldTypes)iI) != iNewYield)
{
iOldYield = getYield((YieldTypes)iI);
m_aiYield[iI] = iNewYield;
FAssert(getYield((YieldTypes)iI) >= 0);
pWorkingCity = getWorkingCity();
if (pWorkingCity != NULL)
{
if (isBeingWorked())
{
pWorkingCity->changeBaseYieldRate(((YieldTypes)iI), (getYield((YieldTypes)iI) - iOldYield));
}
pWorkingCity->AI_setAssignWorkDirty(true);
}
bChange = true;
}
}
if (bChange)
{
updateSymbols();
}
}
int CvPlot::getCulture(PlayerTypes eIndex) const
{
FAssertMsg(eIndex >= 0, "iIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < MAX_PLAYERS, "iIndex is expected to be within maximum bounds (invalid Index)");
return m_aiCulture[eIndex];
}
int CvPlot::countTotalCulture() const
{
int iTotalCulture;
int iI;
iTotalCulture = 0;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
iTotalCulture += getCulture((PlayerTypes)iI);
}
}
return iTotalCulture;
}
TeamTypes CvPlot::findHighestCultureTeam() const
{
TeamTypes eBestTeam;
int iValue;
int iBestValue;
int iI;
iBestValue = 0;
eBestTeam = NO_TEAM;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
iValue = getCulture((PlayerTypes)iI);
if (iValue > iBestValue)
{
iBestValue = iValue;
eBestTeam = GET_PLAYER((PlayerTypes)iI).getTeam();
}
}
}
return eBestTeam;
}
int CvPlot::calculateCulturePercent(PlayerTypes eIndex) const
{
int iTotalCulture;
iTotalCulture = countTotalCulture();
if (iTotalCulture > 0)
{
return ((getCulture(eIndex) * 100) / iTotalCulture);
}
return 0;
}
int CvPlot::calculateTeamCulturePercent(TeamTypes eIndex) const
{
int iTeamCulturePercent;
int iI;
iTeamCulturePercent = 0;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
if (GET_PLAYER((PlayerTypes)iI).getTeam() == eIndex)
{
iTeamCulturePercent += calculateCulturePercent((PlayerTypes)iI);
}
}
}
return iTeamCulturePercent;
}
void CvPlot::setCulture(PlayerTypes eIndex, int iNewValue, bool bUpdate)
{
CvCity* pCity;
FAssertMsg(eIndex >= 0, "iIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < MAX_PLAYERS, "iIndex is expected to be within maximum bounds (invalid Index)");
if (getCulture(eIndex) != iNewValue)
{
m_aiCulture[eIndex] = iNewValue;
FAssert(getCulture(eIndex) >= 0);
if (bUpdate)
{
updateCulture();
}
pCity = getPlotCity();
if (pCity != NULL)
{
pCity->AI_setAssignWorkDirty(true);
}
}
}
void CvPlot::changeCulture(PlayerTypes eIndex, int iChange, bool bUpdate)
{
setCulture(eIndex, (getCulture(eIndex) + iChange), bUpdate);
}
int CvPlot::getFoundValue(PlayerTypes eIndex)
{
FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < MAX_PLAYERS, "eIndex is expected to be within maximum bounds (invalid Index)");
if (m_aiFoundValue[eIndex] == -1)
{
m_aiFoundValue[eIndex] = GET_PLAYER(eIndex).AI_foundValue(getX_INLINE(), getY_INLINE(), -1, true);
if (m_aiFoundValue[eIndex] > area()->getBestFoundValue(eIndex))
{
area()->setBestFoundValue(eIndex, m_aiFoundValue[eIndex]);
}
}
return m_aiFoundValue[eIndex];
}
bool CvPlot::isBestAdjacentFound(PlayerTypes eIndex)
{
CvPlot* pAdjacentPlot;
int iI;
if (getFoundValue(eIndex) == 0)
{
return false;
}
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->getFoundValue(eIndex) >= getFoundValue(eIndex))
{
return false;
}
}
}
return true;
}
void CvPlot::setFoundValue(PlayerTypes eIndex, int iNewValue)
{
FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < MAX_PLAYERS, "eIndex is expected to be within maximum bounds (invalid Index)");
FAssert((iNewValue == -1) || (iNewValue >= 0));
m_aiFoundValue[eIndex] = iNewValue;
}
int CvPlot::getPlayerCityRadiusCount(PlayerTypes eIndex) const
{
FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < MAX_PLAYERS, "eIndex is expected to be within maximum bounds (invalid Index)");
return m_aiPlayerCityRadiusCount[eIndex];
}
bool CvPlot::isPlayerCityRadius(PlayerTypes eIndex) const
{
return (getPlayerCityRadiusCount(eIndex) > 0);
}
void CvPlot::changePlayerCityRadiusCount(PlayerTypes eIndex, int iChange)
{
FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < MAX_PLAYERS, "eIndex is expected to be within maximum bounds (invalid Index)");
m_aiPlayerCityRadiusCount[eIndex] = (m_aiPlayerCityRadiusCount[eIndex] + iChange);
FAssert(getPlayerCityRadiusCount(eIndex) >= 0);
}
CvPlotGroup* CvPlot::getPlotGroup(PlayerTypes ePlayer) const
{
FAssertMsg(ePlayer >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(ePlayer < MAX_PLAYERS, "ePlayer is expected to be within maximum bounds (invalid Index)");
return GET_PLAYER(ePlayer).getPlotGroup(m_aiPlotGroup[ePlayer]);
}
CvPlotGroup* CvPlot::getOwnerPlotGroup() const
{
if (getOwnerINLINE() == NO_PLAYER)
{
return NULL;
}
return getPlotGroup(getOwnerINLINE());
}
void CvPlot::setPlotGroup(PlayerTypes ePlayer, CvPlotGroup* pNewValue)
{
CvPlotGroup* pOldPlotGroup;
CvCity* pCity;
int iI;
pOldPlotGroup = getPlotGroup(ePlayer);
if (pOldPlotGroup != pNewValue)
{
pCity = getPlotCity();
if (ePlayer == getOwnerINLINE())
{
updatePlotGroupBonus(false);
}
if (pOldPlotGroup != NULL)
{
if (pCity != NULL)
{
if (pCity->getOwnerINLINE() == ePlayer)
{
FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlot::setPlotGroup");
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
pCity->changeNumBonuses(((BonusTypes)iI), -(pOldPlotGroup->getNumBonuses((BonusTypes)iI)));
}
}
}
}
if (pNewValue == NULL)
{
m_aiPlotGroup[ePlayer] = FFreeList::INVALID_INDEX;
}
else
{
m_aiPlotGroup[ePlayer] = pNewValue->getID();
}
if (getPlotGroup(ePlayer) != NULL)
{
if (pCity != NULL)
{
if (pCity->getOwnerINLINE() == ePlayer)
{
FAssertMsg((0 < GC.getNumBonusInfos()), "GC.getNumBonusInfos() is not greater than zero but an array is being allocated in CvPlot::setPlotGroup");
for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
{
pCity->changeNumBonuses(((BonusTypes)iI), getPlotGroup(ePlayer)->getNumBonuses((BonusTypes)iI));
}
}
}
}
if (ePlayer == getOwnerINLINE())
{
updatePlotGroupBonus(true);
}
}
}
void CvPlot::updatePlotGroup()
{
int iI;
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
updatePlotGroup((PlayerTypes)iI);
}
}
}
void CvPlot::updatePlotGroup(PlayerTypes ePlayer, bool bRecalculate)
{
PROFILE_FUNC();
CvPlotGroup* pPlotGroup;
CvPlotGroup* pAdjacentPlotGroup;
CvPlot* pAdjacentPlot;
bool bConnected;
bool bEmpty;
int iI;
if (!(GC.getGameINLINE().isFinalInitialized()))
{
return;
}
pPlotGroup = getPlotGroup(ePlayer);
if (pPlotGroup != NULL)
{
if (bRecalculate)
{
bConnected = false;
if (isTradeNetwork(GET_PLAYER(ePlayer).getTeam()))
{
bConnected = true;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->getPlotGroup(ePlayer) == pPlotGroup)
{
if (!isTradeNetworkConnected(pAdjacentPlot, GET_PLAYER(ePlayer).getTeam()))
{
bConnected = false;
break;
}
}
}
}
}
if (!bConnected)
{
bEmpty = (pPlotGroup->getLengthPlots() == 1);
FAssertMsg(pPlotGroup->getLengthPlots() > 0, "pPlotGroup should have more than 0 plots");
pPlotGroup->removePlot(this);
if (!bEmpty)
{
pPlotGroup->recalculatePlots();
}
}
}
pPlotGroup = getPlotGroup(ePlayer);
}
if (isTradeNetwork(GET_PLAYER(ePlayer).getTeam()))
{
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
pAdjacentPlotGroup = pAdjacentPlot->getPlotGroup(ePlayer);
if ((pAdjacentPlotGroup != NULL) && (pAdjacentPlotGroup != pPlotGroup))
{
if (isTradeNetworkConnected(pAdjacentPlot, GET_PLAYER(ePlayer).getTeam()))
{
if (pPlotGroup == NULL)
{
pAdjacentPlotGroup->addPlot(this);
pPlotGroup = pAdjacentPlotGroup;
FAssertMsg(getPlotGroup(ePlayer) == pPlotGroup, "ePlayer's plot group is expected to equal pPlotGroup");
}
else
{
FAssertMsg(getPlotGroup(ePlayer) == pPlotGroup, "ePlayer's plot group is expected to equal pPlotGroup");
GC.getMapINLINE().combinePlotGroups(ePlayer, pPlotGroup, pAdjacentPlotGroup);
pPlotGroup = getPlotGroup(ePlayer);
FAssertMsg(pPlotGroup != NULL, "PlotGroup is not assigned a valid value");
}
}
}
}
}
if (pPlotGroup == NULL)
{
GET_PLAYER(ePlayer).initPlotGroup(this);
}
}
}
int CvPlot::getVisibilityCount(TeamTypes eTeam) const
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
return m_aiVisibilityCount[eTeam];
}
void CvPlot::changeVisibilityCount(TeamTypes eTeam, int iChange, InvisibleTypes eSeeInvisible)
{
PROFILE_FUNC();
CvCity* pCity;
CvPlot* pAdjacentPlot;
bool bOldVisible;
int iI;
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
if (iChange != 0)
{
bOldVisible = isVisible(eTeam, false);
m_aiVisibilityCount[eTeam] = (m_aiVisibilityCount[eTeam] + iChange);
FAssert(getVisibilityCount(eTeam) >= 0);
if (eSeeInvisible != NO_INVISIBLE)
{
changeInvisibleVisibilityCount(eTeam, eSeeInvisible, iChange);
}
if (bOldVisible != isVisible(eTeam, false))
{
PROFILE("CvPlot::changeVisibilityCount 1");
if (isVisible(eTeam, false))
{
PROFILE("CvPlot::changeVisibilityCount 2");
setRevealed(eTeam, true);
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
pAdjacentPlot->updateRevealedOwner(eTeam);
}
}
if (getTeam() != NO_TEAM)
{
GET_TEAM(getTeam()).meet(eTeam, true);
}
}
pCity = getPlotCity();
if (pCity != NULL)
{
pCity->setInfoDirty(true);
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
PROFILE("CvPlot::changeVisibilityCount 4");
if (GET_TEAM((TeamTypes)iI).isAlive())
{
PROFILE("CvPlot::changeVisibilityCount 4.1");
if (GET_TEAM((TeamTypes)iI).isStolenVisibility(eTeam))
{
PROFILE("CvPlot::changeVisibilityCount 4.2");
changeStolenVisibilityCount(((TeamTypes)iI), ((isVisible(eTeam, false)) ? 1 : -1));
}
}
}
if (eTeam == GC.getGameINLINE().getActiveTeam())
{
PROFILE("CvPlot::changeVisibilityCount 3");
updateFog();
updateMinimapColor();
updateCenterUnit();
}
}
}
}
int CvPlot::getStolenVisibilityCount(TeamTypes eTeam) const
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
return m_aiStolenVisibilityCount[eTeam];
}
void CvPlot::changeStolenVisibilityCount(TeamTypes eTeam, int iChange)
{
CvCity* pCity;
bool bOldVisible;
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
if (iChange != 0)
{
bOldVisible = isVisible(eTeam, false);
m_aiStolenVisibilityCount[eTeam] = (m_aiStolenVisibilityCount[eTeam] + iChange);
FAssert(getStolenVisibilityCount(eTeam) >= 0);
if (bOldVisible != isVisible(eTeam, false))
{
if (isVisible(eTeam, false))
{
setRevealed(eTeam, true);
}
pCity = getPlotCity();
if (pCity != NULL)
{
pCity->setInfoDirty(true);
}
if (eTeam == GC.getGameINLINE().getActiveTeam())
{
updateFog();
updateMinimapColor();
updateCenterUnit();
}
}
}
}
PlayerTypes CvPlot::getRevealedOwner(TeamTypes eTeam, bool bDebug) const
{
if (bDebug && GC.getGameINLINE().isDebugMode())
{
return getOwnerINLINE();
}
else
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
return (PlayerTypes)m_aiRevealedOwner[eTeam];
}
}
TeamTypes CvPlot::getRevealedTeam(TeamTypes eTeam, bool bDebug) const
{
PlayerTypes eRevealedOwner;
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
eRevealedOwner = getRevealedOwner(eTeam, bDebug);
if (eRevealedOwner != NO_PLAYER)
{
return GET_PLAYER(eRevealedOwner).getTeam();
}
else
{
return NO_TEAM;
}
}
void CvPlot::setRevealedOwner(TeamTypes eTeam, PlayerTypes eNewValue)
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
if (getRevealedOwner(eTeam, false) != eNewValue)
{
m_aiRevealedOwner[eTeam] = eNewValue;
if (eTeam == GC.getGameINLINE().getActiveTeam())
{
updateMinimapColor();
if (GC.IsGraphicsInitialized())
{
gDLL->getInterfaceIFace()->setDirty(GlobeLayer_DIRTY_BIT, true);
gDLL->getEngineIFace()->SetDirty(CultureBorders_DIRTY_BIT, true);
}
}
}
FAssert(m_aiRevealedOwner[eTeam] == eNewValue);
}
void CvPlot::updateRevealedOwner(TeamTypes eTeam)
{
PROFILE_FUNC();
CvPlot* pAdjacentPlot;
bool bRevealed;
int iI;
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
bRevealed = false;
if (!bRevealed)
{
if (isVisible(eTeam, false))
{
bRevealed = true;
}
}
if (!bRevealed)
{
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
if (pAdjacentPlot->isVisible(eTeam, false))
{
bRevealed = true;
break;
}
}
}
}
setRevealedOwner(eTeam, ((bRevealed) ? getOwnerINLINE() : NO_PLAYER));
}
bool CvPlot::isRiverCrossing(DirectionTypes eIndex) const
{
FAssertMsg(eIndex < NUM_DIRECTION_TYPES, "eTeam is expected to be within maximum bounds (invalid Index)");
if (eIndex == NO_DIRECTION)
{
return false;
}
return m_abRiverCrossing[eIndex];
}
void CvPlot::updateRiverCrossing(DirectionTypes eIndex)
{
CvPlot* pNorthEastPlot;
CvPlot* pSouthEastPlot;
CvPlot* pSouthWestPlot;
CvPlot* pNorthWestPlot;
CvPlot* pCornerPlot;
CvPlot* pPlot;
bool bValid;
FAssertMsg(eIndex >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < NUM_DIRECTION_TYPES, "eTeam is expected to be within maximum bounds (invalid Index)");
pCornerPlot = NULL;
bValid = false;
switch (eIndex)
{
case DIRECTION_NORTH:
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTH);
if (pPlot != NULL)
{
bValid = pPlot->isNOfRiver();
}
break;
case DIRECTION_NORTHEAST:
pCornerPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTH);
break;
case DIRECTION_EAST:
bValid = isWOfRiver();
break;
case DIRECTION_SOUTHEAST:
pCornerPlot = this;
break;
case DIRECTION_SOUTH:
bValid = isNOfRiver();
break;
case DIRECTION_SOUTHWEST:
pCornerPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_WEST);
break;
case DIRECTION_WEST:
pPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_WEST);
if (pPlot != NULL)
{
bValid = pPlot->isWOfRiver();
}
break;
case DIRECTION_NORTHWEST:
pCornerPlot = plotDirection(getX_INLINE(), getY_INLINE(), DIRECTION_NORTHWEST);
break;
default:
FAssert(false);
break;
}
if (pCornerPlot != NULL)
{
pNorthEastPlot = plotDirection(pCornerPlot->getX_INLINE(), pCornerPlot->getY_INLINE(), DIRECTION_EAST);
pSouthEastPlot = plotDirection(pCornerPlot->getX_INLINE(), pCornerPlot->getY_INLINE(), DIRECTION_SOUTHEAST);
pSouthWestPlot = plotDirection(pCornerPlot->getX_INLINE(), pCornerPlot->getY_INLINE(), DIRECTION_SOUTH);
pNorthWestPlot = pCornerPlot;
if ((pSouthWestPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pSouthWestPlot->isWOfRiver() && pNorthWestPlot->isWOfRiver())
{
bValid = true;
}
}
if ((pNorthEastPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pNorthEastPlot->isNOfRiver() && pNorthWestPlot->isNOfRiver())
{
bValid = true;
}
}
if ((eIndex == DIRECTION_NORTHEAST) || (eIndex == DIRECTION_SOUTHWEST))
{
if ((pNorthEastPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pNorthEastPlot->isNOfRiver() && pNorthWestPlot->isWOfRiver())
{
bValid = true;
}
}
if ((pSouthWestPlot != NULL) && (pNorthWestPlot != NULL))
{
if (pSouthWestPlot->isWOfRiver() && pNorthWestPlot->isNOfRiver())
{
bValid = true;
}
}
}
else
{
FAssert((eIndex == DIRECTION_SOUTHEAST) || (eIndex == DIRECTION_NORTHWEST));
if (pNorthWestPlot != NULL)
{
if (pNorthWestPlot->isNOfRiver() && pNorthWestPlot->isWOfRiver())
{
bValid = true;
}
}
if ((pNorthEastPlot != NULL) && (pSouthWestPlot != NULL))
{
if (pNorthEastPlot->isNOfRiver() && pSouthWestPlot->isWOfRiver())
{
bValid = true;
}
}
}
}
if (isRiverCrossing(eIndex) != bValid)
{
m_abRiverCrossing[eIndex] = bValid;
changeRiverCrossingCount((isRiverCrossing(eIndex)) ? 1 : -1);
}
}
void CvPlot::updateRiverCrossing()
{
int iI;
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
updateRiverCrossing((DirectionTypes)iI);
}
}
bool CvPlot::isRevealed(TeamTypes eTeam, bool bDebug) const
{
if (bDebug && GC.getGameINLINE().isDebugMode())
{
return true;
}
else
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
return m_abRevealed[eTeam];
}
}
void CvPlot::setRevealed(TeamTypes eTeam, bool bNewValue, bool bTerrainOnly, TeamTypes eFromTeam)
{
CvCity* pCity;
int iI;
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
pCity = getPlotCity();
if (isRevealed(eTeam, false) != bNewValue)
{
m_abRevealed[eTeam] = bNewValue;
if (area())
{
area()->changeNumRevealedTiles(eTeam, ((isRevealed(eTeam, false)) ? 1 : -1));
}
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).isAlive())
{
if (GET_PLAYER((PlayerTypes)iI).getTeam() == eTeam)
{
updatePlotGroup((PlayerTypes)iI);
}
}
}
if (eTeam == GC.getGameINLINE().getActiveTeam())
{
updateSymbols();
updateFog();
updateVisibility();
gDLL->getInterfaceIFace()->setDirty(MinimapSection_DIRTY_BIT, true);
gDLL->getInterfaceIFace()->setDirty(GlobeLayer_DIRTY_BIT, true);
}
if (isRevealed(eTeam, false))
{
// ONEVENT - PlotRevealed
gDLL->getEventReporterIFace()->plotRevealed(this, eTeam);
}
}
if (!bTerrainOnly)
{
if (isRevealed(eTeam, false))
{
if (eFromTeam == NO_TEAM)
{
setRevealedOwner(eTeam, getOwnerINLINE());
setRevealedImprovementType(eTeam, getImprovementType());
setRevealedRouteType(eTeam, getRouteType());
if (pCity != NULL)
{
pCity->setRevealed(eTeam, true);
}
}
else
{
if (getRevealedOwner(eFromTeam, false) == getOwnerINLINE())
{
setRevealedOwner(eTeam, getRevealedOwner(eFromTeam, false));
}
if (getRevealedImprovementType(eFromTeam, false) == getImprovementType())
{
setRevealedImprovementType(eTeam, getRevealedImprovementType(eFromTeam, false));
}
if (getRevealedRouteType(eFromTeam, false) == getRouteType())
{
setRevealedRouteType(eTeam, getRevealedRouteType(eFromTeam, false));
}
if (pCity != NULL)
{
if (pCity->isRevealed(eFromTeam, false))
{
pCity->setRevealed(eTeam, true);
}
}
}
}
else
{
setRevealedOwner(eTeam, NO_PLAYER);
setRevealedImprovementType(eTeam, NO_IMPROVEMENT);
setRevealedRouteType(eTeam, NO_ROUTE);
if (pCity != NULL)
{
pCity->setRevealed(eTeam, false);
}
}
}
}
ImprovementTypes CvPlot::getRevealedImprovementType(TeamTypes eTeam, bool bDebug) const
{
if (bDebug && GC.getGameINLINE().isDebugMode())
{
return getImprovementType();
}
else
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
return (ImprovementTypes)m_aeRevealedImprovementType[eTeam];
}
}
void CvPlot::setRevealedImprovementType(TeamTypes eTeam, ImprovementTypes eNewValue)
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
if (getRevealedImprovementType(eTeam, false) != eNewValue)
{
m_aeRevealedImprovementType[eTeam] = eNewValue;
if (eTeam == GC.getGameINLINE().getActiveTeam())
{
updateSymbols();
setLayoutDirty(true);
//gDLL->getEngineIFace()->SetDirty(GlobeTexture_DIRTY_BIT, true);
}
}
}
RouteTypes CvPlot::getRevealedRouteType(TeamTypes eTeam, bool bDebug) const
{
if (bDebug && GC.getGameINLINE().isDebugMode())
{
return getRouteType();
}
else
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
return (RouteTypes)m_aeRevealedRouteType[eTeam];
}
}
void CvPlot::setRevealedRouteType(TeamTypes eTeam, RouteTypes eNewValue)
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
if (getRevealedRouteType(eTeam, false) != eNewValue)
{
m_aeRevealedRouteType[eTeam] = eNewValue;
if (eTeam == GC.getGameINLINE().getActiveTeam())
{
updateSymbols();
updateRouteSymbol(true, true);
}
}
}
int CvPlot::getBuildProgress(BuildTypes eBuild) const
{
return m_paiBuildProgress[eBuild];
}
// Returns true if build finished...
bool CvPlot::changeBuildProgress(BuildTypes eBuild, int iChange, TeamTypes eTeam)
{
CvCity* pCity;
wchar szBuffer[1024];
int iProduction;
bool bFinished;
bFinished = false;
if (iChange != 0)
{
m_paiBuildProgress[eBuild] = (m_paiBuildProgress[eBuild] + iChange);
FAssert(getBuildProgress(eBuild) >= 0);
if (getBuildProgress(eBuild) >= getBuildTime(eBuild))
{
m_paiBuildProgress[eBuild] = 0;
if (GC.getBuildInfo(eBuild).getImprovement() != NO_IMPROVEMENT)
{
setImprovementType((ImprovementTypes)GC.getBuildInfo(eBuild).getImprovement());
}
if (GC.getBuildInfo(eBuild).getRoute() != NO_ROUTE)
{
setRouteType((RouteTypes)GC.getBuildInfo(eBuild).getRoute());
}
if (getFeatureType() != NO_FEATURE)
{
if (GC.getBuildInfo(eBuild).isFeatureRemove(getFeatureType()))
{
FAssertMsg(eTeam != NO_TEAM, "eTeam should be valid");
iProduction = getFeatureProduction(eBuild, eTeam, &pCity);
if (iProduction > 0)
{
pCity->changeProduction(iProduction);
swprintf(szBuffer, gDLL->getText("TXT_KEY_MISC_CLEARING_FEATURE_BONUS", GC.getFeatureInfo(getFeatureType()).getTextKeyWide(), iProduction, pCity->getNameKey()).GetCString());
gDLL->getInterfaceIFace()->addMessage(pCity->getOwnerINLINE(), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, ARTFILEMGR.getInterfaceArtInfo("WORLDBUILDER_CITY_EDIT")->getPath(), MESSAGE_TYPE_INFO, GC.getFeatureInfo(getFeatureType()).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE(), true, true);
}
setFeatureType(NO_FEATURE);
}
}
bFinished = true;
}
}
return bFinished;
}
void CvPlot::updateFeatureSymbolVisibility()
{
PROFILE_FUNC();
if (!GC.IsGraphicsInitialized())
{
return;
}
if (m_pFeatureSymbol != NULL)
{
gDLL->getFeatureIFace()->Hide(m_pFeatureSymbol, !(isRevealed(GC.getGameINLINE().getActiveTeam(), true)));
}
}
void CvPlot::updateFeatureSymbol(bool bForce)
{
PROFILE_FUNC();
FeatureTypes eFeature;
if (!GC.IsGraphicsInitialized())
{
return;
}
eFeature = getFeatureType();
gDLL->getEngineIFace()->RebuildTileArt(m_iX,m_iY);
if ((eFeature == NO_FEATURE) ||
(GC.getFeatureInfo(eFeature).getArtInfo()->isRiverArt()) ||
(GC.getFeatureInfo(eFeature).getArtInfo()->isTileArt()))
{
gDLL->getFeatureIFace()->destroy(m_pFeatureSymbol);
return;
}
if (bForce || (m_pFeatureSymbol == NULL) || (gDLL->getFeatureIFace()->getFeature(m_pFeatureSymbol) != eFeature))
{
gDLL->getFeatureIFace()->destroy(m_pFeatureSymbol);
m_pFeatureSymbol = gDLL->getFeatureIFace()->createFeature();
FAssertMsg(m_pFeatureSymbol != NULL, "m_pFeatureSymbol is not expected to be equal with NULL");
gDLL->getFeatureIFace()->init(m_pFeatureSymbol, 0, 0, eFeature, this);
updateFeatureSymbolVisibility();
}
else
{
gDLL->getEntityIFace()->updatePosition((CvEntity*)m_pFeatureSymbol); //update position and contours
}
}
CvRoute* CvPlot::getRouteSymbol() const
{
return m_pRouteSymbol;
}
// XXX route symbols don't really exist anymore...
void CvPlot::updateRouteSymbol(bool bForce, bool bAdjacent)
{
PROFILE_FUNC();
CvPlot* pAdjacentPlot;
RouteTypes eRoute;
int iI;
if (!GC.IsGraphicsInitialized())
{
return;
}
if (bAdjacent)
{
for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)iI));
if (pAdjacentPlot != NULL)
{
pAdjacentPlot->updateRouteSymbol(bForce, false);
//pAdjacentPlot->setLayoutDirty(true);
}
}
}
eRoute = getRevealedRouteType(GC.getGameINLINE().getActiveTeam(), true);
if (eRoute == NO_ROUTE)
{
gDLL->getRouteIFace()->destroy(m_pRouteSymbol);
return;
}
if (bForce || (m_pRouteSymbol == NULL) || (gDLL->getRouteIFace()->getRoute(m_pRouteSymbol) != eRoute))
{
gDLL->getRouteIFace()->destroy(m_pRouteSymbol);
m_pRouteSymbol = gDLL->getRouteIFace()->createRoute();
FAssertMsg(m_pRouteSymbol != NULL, "m_pRouteSymbol is not expected to be equal with NULL");
gDLL->getRouteIFace()->init(m_pRouteSymbol, 0, 0, eRoute, this);
setLayoutDirty(true);
}
else
{
gDLL->getEntityIFace()->updatePosition((CvEntity *)m_pRouteSymbol); //update position and contours
}
}
CvRiver* CvPlot::getRiverSymbol() const
{
return m_pRiverSymbol;
}
CvFeature* CvPlot::getFeatureSymbol() const
{
return m_pFeatureSymbol;
}
void CvPlot::updateRiverSymbol(bool bForce, bool bAdjacent)
{
PROFILE_FUNC();
CvPlot* pAdjacentPlot;
if (!GC.IsGraphicsInitialized())
{
return;
}
if (bAdjacent)
{
for(int i=0;i<NUM_DIRECTION_TYPES;i++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)i));
if (pAdjacentPlot != NULL)
{
pAdjacentPlot->updateRiverSymbol(bForce, false);
//pAdjacentPlot->setLayoutDirty(true);
}
}
}
if (!isRiverMask())
{
gDLL->getRiverIFace()->destroy(m_pRiverSymbol);
return;
}
if (bForce || (m_pRiverSymbol == NULL))
{
//create river
gDLL->getRiverIFace()->destroy(m_pRiverSymbol);
m_pRiverSymbol = gDLL->getRiverIFace()->createRiver();
FAssertMsg(m_pRiverSymbol != NULL, "m_pRiverSymbol is not expected to be equal with NULL");
gDLL->getRiverIFace()->init(m_pRiverSymbol, 0, 0, 0, this);
//force tree cuts for adjacent plots
DirectionTypes affectedDirections[] = {NO_DIRECTION, DIRECTION_EAST, DIRECTION_SOUTHEAST, DIRECTION_SOUTH};
for(int i=0;i<4;i++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), affectedDirections[i]);
if (pAdjacentPlot != NULL)
{
gDLL->getEngineIFace()->ForceTreeOffsets(pAdjacentPlot->getX(), pAdjacentPlot->getY());
}
}
//cut out canyons
gDLL->getEngineIFace()->RebuildRiverPlotTile(getX_INLINE(), getY_INLINE(), true, false);
//recontour adjacent rivers
for(int i=0;i<NUM_DIRECTION_TYPES;i++)
{
pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), ((DirectionTypes)i));
if((pAdjacentPlot != NULL) && (pAdjacentPlot->m_pRiverSymbol != NULL))
{
gDLL->getEntityIFace()->updatePosition((CvEntity *)pAdjacentPlot->m_pRiverSymbol); //update position and contours
}
}
// update the symbol
setLayoutDirty(true);
}
//recontour rivers
gDLL->getEntityIFace()->updatePosition((CvEntity *)m_pRiverSymbol); //update position and contours
}
void CvPlot::updateRiverSymbolArt(bool bAdjacent)
{
//this is used to update floodplain features
gDLL->getEntityIFace()->setupFloodPlains(m_pRiverSymbol);
if(bAdjacent)
{
for(int i=0;i<NUM_DIRECTION_TYPES;i++)
{
CvPlot *pAdjacentPlot = plotDirection(getX_INLINE(), getY_INLINE(), (DirectionTypes) i);
if((pAdjacentPlot != NULL) && (pAdjacentPlot->m_pRiverSymbol != NULL))
{
gDLL->getEntityIFace()->setupFloodPlains(pAdjacentPlot->m_pRiverSymbol);
}
}
}
}
CvFlagEntity* CvPlot::getFlagSymbol() const
{
return m_pFlagSymbol;
}
CvFlagEntity* CvPlot::getFlagSymbolOffset() const
{
return m_pFlagSymbolOffset;
}
void CvPlot::updateFlagSymbol()
{
PROFILE_FUNC();
if (!GC.IsGraphicsInitialized())
{
return;
}
PlayerTypes ePlayer = NO_PLAYER;
PlayerTypes ePlayerOffset = NO_PLAYER;
CvUnit* pCenterUnit = getCenterUnit();
//get the plot's unit's flag
if (pCenterUnit != NULL)
{
ePlayer = pCenterUnit->getOwnerINLINE();
}
//get moving unit's flag
if (gDLL->getInterfaceIFace()->getSingleMoveGotoPlot() == this)
{
if(ePlayer == NO_PLAYER)
{
ePlayer = GC.getGameINLINE().getActivePlayer();
}
else
{
ePlayerOffset = GC.getGameINLINE().getActivePlayer();
}
}
//don't put two of the same flags
if(ePlayerOffset == ePlayer)
{
ePlayerOffset = NO_PLAYER;
}
//destroy old flags
if (ePlayer == NO_PLAYER)
{
gDLL->getFlagEntityIFace()->destroy(m_pFlagSymbol);
}
if (ePlayerOffset == NO_PLAYER)
{
gDLL->getFlagEntityIFace()->destroy(m_pFlagSymbolOffset);
}
//create and/or update unit's flag
if (ePlayer != NO_PLAYER)
{
if ((m_pFlagSymbol == NULL) || (gDLL->getFlagEntityIFace()->getPlayer(m_pFlagSymbol) != ePlayer))
{
if (m_pFlagSymbol != NULL)
{
gDLL->getFlagEntityIFace()->destroy(m_pFlagSymbol);
}
m_pFlagSymbol = gDLL->getFlagEntityIFace()->create(ePlayer);
if (m_pFlagSymbol != NULL)
{
gDLL->getFlagEntityIFace()->setPlot(m_pFlagSymbol, this, false);
}
}
if (m_pFlagSymbol != NULL)
{
gDLL->getFlagEntityIFace()->updateUnitInfo(m_pFlagSymbol, this);
}
}
//create and/or update offset flag
if (ePlayerOffset != NO_PLAYER)
{
if ((m_pFlagSymbolOffset == NULL) || (gDLL->getFlagEntityIFace()->getPlayer(m_pFlagSymbolOffset) != ePlayerOffset))
{
if (m_pFlagSymbolOffset != NULL)
{
gDLL->getFlagEntityIFace()->destroy(m_pFlagSymbolOffset);
}
m_pFlagSymbolOffset = gDLL->getFlagEntityIFace()->create(ePlayerOffset);
if (m_pFlagSymbolOffset != NULL)
{
gDLL->getFlagEntityIFace()->setPlot(m_pFlagSymbolOffset, this, true);
}
}
}
}
CvUnit* CvPlot::getCenterUnit() const
{
return m_pCenterUnit;
}
CvUnit* CvPlot::getDebugCenterUnit() const
{
CvUnit* pCenterUnit;
pCenterUnit = getCenterUnit();
if (pCenterUnit == NULL)
{
if (GC.getGameINLINE().isDebugMode())
{
pCenterUnit = getUnit(0);
}
}
return pCenterUnit;
}
void CvPlot::setCenterUnit(CvUnit* pNewValue)
{
CvUnit* pOldValue;
pOldValue = getCenterUnit();
if (pOldValue != pNewValue)
{
m_pCenterUnit = pNewValue;
setFlagDirty(true);
if (getCenterUnit() != NULL)
{
getCenterUnit()->setInfoBarDirty(true);
}
}
}
int CvPlot::getCultureRangeCities(PlayerTypes eOwnerIndex, int iRangeIndex) const
{
FAssert(eOwnerIndex >= 0);
FAssert(eOwnerIndex < MAX_PLAYERS);
FAssert(iRangeIndex >= 0);
FAssert(iRangeIndex < GC.getNumCultureLevelInfos());
return m_apaiCultureRangeCities[eOwnerIndex][iRangeIndex];
}
bool CvPlot::isCultureRangeCity(PlayerTypes eOwnerIndex, int iRangeIndex) const
{
return (getCultureRangeCities(eOwnerIndex, iRangeIndex) > 0);
}
void CvPlot::changeCultureRangeCities(PlayerTypes eOwnerIndex, int iRangeIndex, int iChange)
{
bool bOldCultureRangeCities;
FAssert(eOwnerIndex >= 0);
FAssert(eOwnerIndex < MAX_PLAYERS);
FAssert(iRangeIndex >= 0);
FAssert(iRangeIndex < GC.getNumCultureLevelInfos());
bOldCultureRangeCities = isCultureRangeCity(eOwnerIndex, iRangeIndex);
m_apaiCultureRangeCities[eOwnerIndex][iRangeIndex] = (m_apaiCultureRangeCities[eOwnerIndex][iRangeIndex] + iChange);
if (bOldCultureRangeCities != isCultureRangeCity(eOwnerIndex, iRangeIndex))
{
updateCulture();
}
}
int CvPlot::getInvisibleVisibilityCount(TeamTypes eTeam, InvisibleTypes eInvisible) const
{
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
FAssertMsg(eInvisible >= 0, "eInvisible is expected to be non-negative (invalid Index)");
FAssertMsg(eInvisible < GC.getNumInvisibleInfos(), "eInvisible is expected to be within maximum bounds (invalid Index)");
return m_apaiInvisibleVisibilityCount[eTeam][eInvisible];
}
bool CvPlot::isInvisibleVisible(TeamTypes eTeam, InvisibleTypes eInvisible) const
{
return (getInvisibleVisibilityCount(eTeam, eInvisible) > 0);
}
void CvPlot::changeInvisibleVisibilityCount(TeamTypes eTeam, InvisibleTypes eInvisible, int iChange)
{
bool bOldInvisibleVisible;
FAssertMsg(eTeam >= 0, "eTeam is expected to be non-negative (invalid Index)");
FAssertMsg(eTeam < MAX_TEAMS, "eTeam is expected to be within maximum bounds (invalid Index)");
FAssertMsg(eInvisible >= 0, "eInvisible is expected to be non-negative (invalid Index)");
FAssertMsg(eInvisible < GC.getNumInvisibleInfos(), "eInvisible is expected to be within maximum bounds (invalid Index)");
if (iChange != 0)
{
bOldInvisibleVisible = isInvisibleVisible(eTeam, eInvisible);
m_apaiInvisibleVisibilityCount[eTeam][eInvisible] = (m_apaiInvisibleVisibilityCount[eTeam][eInvisible] + iChange);
if (bOldInvisibleVisible != isInvisibleVisible(eTeam, eInvisible))
{
if (eTeam == GC.getGameINLINE().getActiveTeam())
{
updateCenterUnit();
}
}
}
}
int CvPlot::getNumUnits() const
{
return m_units.getLength();
}
CvUnit* CvPlot::getUnit(int iIndex) const
{
CLLNode<IDInfo>* pUnitNode;
pUnitNode = m_units.nodeNum(iIndex);
if (pUnitNode != NULL)
{
return ::getUnit(pUnitNode->m_data);
}
else
{
return NULL;
}
}
void CvPlot::addUnit(CvUnit* pUnit, bool bUpdate)
{
CLLNode<IDInfo>* pUnitNode;
CvUnit* pLoopUnit;
FAssertMsg(pUnit->at(getX_INLINE(), getY_INLINE()), "pUnit is expected to be at getX_INLINE and getY_INLINE");
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
if (!isBeforeUnitCycle(pLoopUnit, pUnit))
{
break;
}
pUnitNode = nextUnitNode(pUnitNode);
}
if (pUnitNode != NULL)
{
m_units.insertBefore(pUnit->getIDInfo(), pUnitNode);
}
else
{
m_units.insertAtEnd(pUnit->getIDInfo());
}
if (bUpdate)
{
updateCenterUnit();
setFlagDirty(true);
}
}
void CvPlot::removeUnit(CvUnit* pUnit, bool bUpdate)
{
CLLNode<IDInfo>* pUnitNode;
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
if (::getUnit(pUnitNode->m_data) == pUnit)
{
FAssertMsg(::getUnit(pUnitNode->m_data)->at(getX_INLINE(), getY_INLINE()), "The current unit instance is expected to be at getX_INLINE and getY_INLINE");
m_units.deleteNode(pUnitNode);
break;
}
else
{
pUnitNode = nextUnitNode(pUnitNode);
}
}
if (bUpdate)
{
updateCenterUnit();
setFlagDirty(true);
}
}
CLLNode<IDInfo>* CvPlot::nextUnitNode(CLLNode<IDInfo>* pNode) const
{
return m_units.next(pNode);
}
CLLNode<IDInfo>* CvPlot::prevUnitNode(CLLNode<IDInfo>* pNode) const
{
return m_units.prev(pNode);
}
CLLNode<IDInfo>* CvPlot::headUnitNode() const
{
return m_units.head();
}
CLLNode<IDInfo>* CvPlot::tailUnitNode() const
{
return m_units.tail();
}
int CvPlot::getNumSymbols() const
{
return m_symbols.size();
}
CvSymbol* CvPlot::getSymbol(int iID) const
{
return m_symbols[iID];
}
CvSymbol* CvPlot::addSymbol()
{
CvSymbol* pSym=gDLL->getSymbolIFace()->createSymbol();
m_symbols.push_back(pSym);
return pSym;
}
void CvPlot::deleteSymbol(int iID)
{
m_symbols.erase(m_symbols.begin()+iID);
}
void CvPlot::deleteAllSymbols()
{
int i;
for(i=0;i<getNumSymbols();i++)
{
gDLL->getSymbolIFace()->destroy(m_symbols[i]);
}
m_symbols.clear();
}
CvString CvPlot::getScriptData() const
{
return m_szScriptData;
}
void CvPlot::setScriptData(const char* szNewValue)
{
SAFE_DELETE_ARRAY(m_szScriptData);
m_szScriptData = strdup(szNewValue);
}
// Protected Functions...
void CvPlot::doFeature()
{
PROFILE("CvPlot::doFeature()")
CvCity* pCity;
CvPlot* pLoopPlot;
wchar szBuffer[1024];
int iProbability;
int iI, iJ;
if (getFeatureType() != NO_FEATURE)
{
iProbability = GC.getFeatureInfo(getFeatureType()).getDisappearanceProbability();
if (iProbability > 0)
{
if (GC.getGameINLINE().getSorenRandNum(10000, "Feature Disappearance") < iProbability)
{
setFeatureType(NO_FEATURE);
}
}
}
else
{
if (!isUnit())
{
if (getImprovementType() == NO_IMPROVEMENT)
{
for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
{
if (canHaveFeature((FeatureTypes)iI))
{
if ((getBonusType() == NO_BONUS) || (GC.getBonusInfo(getBonusType()).isFeature(iI)))
{
iProbability = 0;
for (iJ = 0; iJ < NUM_CARDINALDIRECTION_TYPES; iJ++)
{
pLoopPlot = plotCardinalDirection(getX_INLINE(), getY_INLINE(), ((CardinalDirectionTypes)iJ));
if (pLoopPlot != NULL)
{
if (pLoopPlot->getImprovementType() == NO_IMPROVEMENT)
{
if (pLoopPlot->getFeatureType() == ((FeatureTypes)iI))
{
iProbability += GC.getFeatureInfo((FeatureTypes)iI).getGrowthProbability();
}
}
}
}
iProbability *= max(0, (GC.getDefineINT("FEATURE_GROWTH_MODIFIER") + 100));
iProbability /= 100;
if (isRoute())
{
iProbability *= max(0, (GC.getDefineINT("ROUTE_FEATURE_GROWTH_MODIFIER") + 100));
iProbability /= 100;
}
if (iProbability > 0)
{
if (GC.getGameINLINE().getSorenRandNum(10000, "Feature Growth") < iProbability)
{
setFeatureType((FeatureTypes)iI);
pCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE(), NO_TEAM, false);
if (pCity != NULL)
{
// Tell the owner of this city.
swprintf(szBuffer, gDLL->getText("TXT_KEY_MISC_FEATURE_GROWN_NEAR_CITY", GC.getFeatureInfo((FeatureTypes) iI).getTextKeyWide(), pCity->getNameKey()).GetCString());
gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_FEATUREGROWTH", MESSAGE_TYPE_INFO, GC.getFeatureInfo((FeatureTypes) iI).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE(), true, true);
}
break;
}
}
}
}
}
}
}
}
}
void CvPlot::doCulture()
{
PROFILE("CvPlot::doCulture()")
CLLNode<IDInfo>* pUnitNode;
CvCity* pCity;
CvUnit* pLoopUnit;
wchar szBuffer[1024];
PlayerTypes eCulturalOwner;
int iGarrison;
int iCityStrength;
pCity = getPlotCity();
if (pCity != NULL)
{
eCulturalOwner = calculateCulturalOwner();
if (eCulturalOwner != NO_PLAYER)
{
if (GET_PLAYER(eCulturalOwner).getTeam() != getTeam())
{
if (!(pCity->isOccupation()))
{
if (GC.getGameINLINE().getSorenRandNum(100, "Revolt #1") < GC.getDefineINT("REVOLT_TEST_PROB"))
{
iCityStrength = pCity->cultureStrength(eCulturalOwner);
iGarrison = pCity->cultureGarrison(eCulturalOwner);
if ((GC.getGameINLINE().getSorenRandNum(iCityStrength, "Revolt #2") > iGarrison) || pCity->isBarbarian())
{
pUnitNode = headUnitNode();
while (pUnitNode != NULL)
{
pLoopUnit = ::getUnit(pUnitNode->m_data);
pUnitNode = nextUnitNode(pUnitNode);
if (pLoopUnit->isBarbarian())
{
pLoopUnit->kill(false, eCulturalOwner);
}
else if (pLoopUnit->canDefend())
{
pLoopUnit->changeDamage((pLoopUnit->currHitPoints() / 2), eCulturalOwner);
}
}
if (pCity->isBarbarian() || (!(GC.getGameINLINE().isOption(GAMEOPTION_NO_CITY_FLIPPING)) && (GC.getGameINLINE().isOption(GAMEOPTION_FLIPPING_AFTER_CONQUEST) || !(pCity->isEverOwned(eCulturalOwner))) && (pCity->getNumRevolts(eCulturalOwner) >= GC.getDefineINT("NUM_WARNING_REVOLTS"))))
{
if (GC.getGameINLINE().isOption(GAMEOPTION_ONE_CITY_CHALLENGE) && GET_PLAYER(eCulturalOwner).isHuman())
{
pCity->kill();
}
else
{
setOwner(eCulturalOwner); // will delete pCity
}
pCity = NULL;
}
else
{
pCity->changeNumRevolts(eCulturalOwner, 1);
pCity->changeOccupationTimer(GC.getDefineINT("BASE_REVOLT_OCCUPATION_TURNS") + ((iCityStrength * GC.getDefineINT("REVOLT_OCCUPATION_TURNS_PERCENT")) / 100));
// XXX announce for all seen cities?
swprintf(szBuffer, gDLL->getText("TXT_KEY_MISC_REVOLT_IN_CITY", GET_PLAYER(eCulturalOwner).getCivilizationAdjective(), pCity->getNameKey()).GetCString());
gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_CITY_REVOLT", MESSAGE_TYPE_MINOR_EVENT, ARTFILEMGR.getInterfaceArtInfo("INTERFACE_RESISTANCE")->getPath(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
gDLL->getInterfaceIFace()->addMessage(eCulturalOwner, false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_CITY_REVOLT", MESSAGE_TYPE_MINOR_EVENT, ARTFILEMGR.getInterfaceArtInfo("INTERFACE_RESISTANCE")->getPath(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
}
}
}
}
}
}
}
updateCulture();
}
void CvPlot::processArea(CvArea* pArea, int iChange)
{
CvCity* pCity;
int iI, iJ;
// XXX am not updating getBestFoundValue() or getAreaAIType()...
pArea->changeNumTiles(iChange);
if (isOwned())
{
pArea->changeNumOwnedTiles(iChange);
}
if (isNOfRiver())
{
pArea->changeNumRiverEdges(iChange);
}
if (isWOfRiver())
{
pArea->changeNumRiverEdges(iChange);
}
if (getBonusType() != NO_BONUS)
{
pArea->changeNumBonuses(getBonusType(), iChange);
}
if (getImprovementType() != NO_IMPROVEMENT)
{
pArea->changeNumImprovements(getImprovementType(), iChange);
}
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (GET_PLAYER((PlayerTypes)iI).getStartingPlot() == this)
{
pArea->changeNumStartingPlots(iChange);
}
pArea->changePower(((PlayerTypes)iI), (getUnitPower((PlayerTypes)iI) * iChange));
pArea->changeUnitsPerPlayer(((PlayerTypes)iI), (plotCount(PUF_isPlayer, iI) * iChange));
pArea->changeAnimalsPerPlayer(((PlayerTypes)iI), (plotCount(PUF_isAnimal, -1, -1, ((PlayerTypes)iI)) * iChange));
for (iJ = 0; iJ < NUM_UNITAI_TYPES; iJ++)
{
pArea->changeNumAIUnits(((PlayerTypes)iI), ((UnitAITypes)iJ), (plotCount(PUF_isUnitAIType, iJ, -1, ((PlayerTypes)iI)) * iChange));
}
}
for (iI = 0; iI < MAX_TEAMS; iI++)
{
if (isRevealed(((TeamTypes)iI), false))
{
pArea->changeNumRevealedTiles(((TeamTypes)iI), iChange);
}
}
pCity = getPlotCity();
if (pCity != NULL)
{
// XXX make sure all of this (esp. the changePower()) syncs up...
pArea->changePower(pCity->getOwnerINLINE(), (getPopulationPower(pCity->getPopulation()) * iChange));
pArea->changeCitiesPerPlayer(pCity->getOwnerINLINE(), iChange);
pArea->changePopulationPerPlayer(pCity->getOwnerINLINE(), (pCity->getPopulation() * iChange));
for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
{
if (pCity->hasActiveBuilding((BuildingTypes)iI))
{
pArea->changePower(pCity->getOwnerINLINE(), (GC.getBuildingInfo((BuildingTypes)iI).getPowerValue() * iChange));
if (GC.getBuildingInfo((BuildingTypes) iI).getAreaHealth() > 0)
{
pArea->changeBuildingGoodHealth(pCity->getOwnerINLINE(), (GC.getBuildingInfo((BuildingTypes)iI).getAreaHealth() * iChange));
}
else
{
pArea->changeBuildingBadHealth(pCity->getOwnerINLINE(), (GC.getBuildingInfo((BuildingTypes)iI).getAreaHealth() * iChange));
}
pArea->changeBuildingHappiness(pCity->getOwnerINLINE(), (GC.getBuildingInfo((BuildingTypes)iI).getAreaHappiness() * iChange));
pArea->changeFreeSpecialist(pCity->getOwnerINLINE(), (GC.getBuildingInfo((BuildingTypes)iI).getAreaFreeSpecialist() * iChange));
pArea->changeCleanPowerCount(pCity->getTeam(), ((GC.getBuildingInfo((BuildingTypes)iI).isAreaCleanPower()) ? iChange : 0));
for (iJ = 0; iJ < NUM_YIELD_TYPES; iJ++)
{
pArea->changeYieldRateModifier(pCity->getOwnerINLINE(), ((YieldTypes)iJ), (GC.getBuildingInfo((BuildingTypes)iI).getAreaYieldModifier(iJ) * iChange));
}
}
}
for (iI = 0; iI < NUM_UNITAI_TYPES; iI++)
{
pArea->changeNumTrainAIUnits(pCity->getOwnerINLINE(), ((UnitAITypes)iI), (pCity->getNumTrainUnitAI((UnitAITypes)iI) * iChange));
}
for (iI = 0; iI < MAX_PLAYERS; iI++)
{
if (pArea->getTargetCity((PlayerTypes)iI) == pCity)
{
pArea->setTargetCity(((PlayerTypes)iI), NULL);
}
}
}
}
ColorTypes CvPlot::plotMinimapColor()
{
CvUnit* pCenterUnit;
if (GC.getGameINLINE().getActivePlayer() != NO_PLAYER)
{
CvCity* pCity;
pCity = getPlotCity();
if ((pCity != NULL) && pCity->isRevealed(GC.getGameINLINE().getActiveTeam(), true))
{
return (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE");
}
if (isActiveVisible(true))
{
pCenterUnit = getDebugCenterUnit();
if (pCenterUnit != NULL)
{
return ((ColorTypes)(GC.getPlayerColorInfo(GET_PLAYER(pCenterUnit->getOwnerINLINE()).getPlayerColor()).getColorTypePrimary()));
}
}
if ((getRevealedOwner(GC.getGameINLINE().getActiveTeam(), true) != NO_PLAYER) && !isRevealedBarbarian())
{
return ((ColorTypes)(GC.getPlayerColorInfo(GET_PLAYER(getRevealedOwner(GC.getGameINLINE().getActiveTeam(), true)).getPlayerColor()).getColorTypePrimary()));
}
}
return (ColorTypes)GC.getInfoTypeForString("COLOR_CLEAR");
}
//
// read object from a stream
// used during load
//
void CvPlot::read(FDataStreamBase* pStream)
{
int iI;
// Init saved data
reset();
uint uiFlag=0;
pStream->Read(&uiFlag); // flags for expansion
pStream->Read(&m_iX);
pStream->Read(&m_iY);
pStream->Read(&m_iArea);
pStream->Read(&m_iFeatureVariety);
if (uiFlag & SAVEDATA_OWNERSHIP_DURATION)
{
pStream->Read(&m_iOwnershipDuration);
}
if (uiFlag & SAVEDATA_IMPROVEMENT_DURATION)
{
pStream->Read(&m_iImprovementDuration);
}
pStream->Read(&m_iUpgradeProgress);
pStream->Read(&m_iForceUnownedTimer);
pStream->Read(&m_iCityRadiusCount);
pStream->Read(&m_iRiverID);
pStream->Read(&m_iMinOriginalStartDist);
pStream->Read(&m_iReconCount);
pStream->Read(&m_iRiverCrossingCount);
bool bVal;
pStream->Read(&bVal);
m_bStartingPlot = bVal;
pStream->Read(&bVal);
m_bHills = bVal;
pStream->Read(&bVal);
m_bNOfRiver = bVal;
pStream->Read(&bVal);
m_bWOfRiver = bVal;
pStream->Read(&bVal);
m_bIrrigated = bVal;
pStream->Read(&bVal);
m_bPotentialCityWork = bVal;
// m_bShowCitySymbols not saved
// m_bFlagDirty not saved
// m_bPlotLayoutDirty not saved
// m_bLayoutStateWorked not saved
pStream->Read(&m_eOwner);
pStream->Read(&m_ePlotType);
pStream->Read(&m_eTerrainType);
pStream->Read(&m_eFeatureType);
pStream->Read(&m_eBonusType);
pStream->Read(&m_eImprovementType);
pStream->Read(&m_eRouteType);
pStream->Read(&m_eRiverNSDirection);
pStream->Read(&m_eRiverWEDirection);
pStream->Read((int*)&m_plotCity.eOwner);
pStream->Read(&m_plotCity.iID);
pStream->Read((int*)&m_workingCity.eOwner);
pStream->Read(&m_workingCity.iID);
pStream->Read((int*)&m_workingCityOverride.eOwner);
pStream->Read(&m_workingCityOverride.iID);
pStream->Read(NUM_YIELD_TYPES, m_aiYield);
pStream->Read(MAX_PLAYERS, m_aiCulture);
pStream->Read(MAX_PLAYERS, m_aiFoundValue);
pStream->Read(MAX_PLAYERS, m_aiPlayerCityRadiusCount);
pStream->Read(MAX_PLAYERS, m_aiPlotGroup);
pStream->Read(MAX_TEAMS, m_aiVisibilityCount);
pStream->Read(MAX_TEAMS, m_aiStolenVisibilityCount);
pStream->Read(MAX_TEAMS, m_aiRevealedOwner);
for(iI=0;iI<NUM_DIRECTION_TYPES;iI++)
{
pStream->Read(&bVal);
m_abRiverCrossing[iI] = bVal;
}
for(iI=0;iI<MAX_TEAMS;iI++)
{
pStream->Read(&bVal);
m_abRevealed[iI] = bVal;
}
pStream->Read(MAX_TEAMS, m_aeRevealedImprovementType);
pStream->Read(MAX_TEAMS, m_aeRevealedRouteType);
if (!(uiFlag & SAVEDATA_NO_LANDMARK))
{
wchar* szLandmark = pStream->ReadWideString();
if((szLandmark != NULL) && (wcslen(szLandmark) > 0))
{
gDLL->getEngineIFace()->addLandmark(this, szLandmark);
}
}
m_szScriptData = pStream->ReadString();
pStream->Read(GC.getNumBuildInfos(), m_paiBuildProgress);
for (iI=0;iI<MAX_PLAYERS;iI++)
{
pStream->Read(GC.getNumCultureLevelInfos(), m_apaiCultureRangeCities[iI]);
}
for (iI=0;iI<MAX_TEAMS;iI++)
{
pStream->Read(GC.getNumInvisibleInfos(), m_apaiInvisibleVisibilityCount[iI]);
}
m_units.Read(pStream);
}
//
// write object to a stream
// used during save
//
void CvPlot::write(FDataStreamBase* pStream)
{
int iI;
uint uiFlag=0;
uiFlag |= SAVEDATA_NO_LANDMARK;
uiFlag |= SAVEDATA_IMPROVEMENT_DURATION;
uiFlag |= SAVEDATA_OWNERSHIP_DURATION;
pStream->Write(uiFlag); // flag for expansion
pStream->Write(m_iX);
pStream->Write(m_iY);
pStream->Write(m_iArea);
pStream->Write(m_iFeatureVariety);
pStream->Write(m_iOwnershipDuration);
pStream->Write(m_iImprovementDuration);
pStream->Write(m_iUpgradeProgress);
pStream->Write(m_iForceUnownedTimer);
pStream->Write(m_iCityRadiusCount);
pStream->Write(m_iRiverID);
pStream->Write(m_iMinOriginalStartDist);
pStream->Write(m_iReconCount);
pStream->Write(m_iRiverCrossingCount);
pStream->Write(m_bStartingPlot);
pStream->Write(m_bHills);
pStream->Write(m_bNOfRiver);
pStream->Write(m_bWOfRiver);
pStream->Write(m_bIrrigated);
pStream->Write(m_bPotentialCityWork);
// m_bShowCitySymbols not saved
// m_bFlagDirty not saved
// m_bPlotLayoutDirty not saved
// m_bLayoutStateWorked not saved
pStream->Write(m_eOwner);
pStream->Write(m_ePlotType);
pStream->Write(m_eTerrainType);
pStream->Write(m_eFeatureType);
pStream->Write(m_eBonusType);
pStream->Write(m_eImprovementType);
pStream->Write(m_eRouteType);
pStream->Write(m_eRiverNSDirection);
pStream->Write(m_eRiverWEDirection);
pStream->Write(m_plotCity.eOwner);
pStream->Write(m_plotCity.iID);
pStream->Write(m_workingCity.eOwner);
pStream->Write(m_workingCity.iID);
pStream->Write(m_workingCityOverride.eOwner);
pStream->Write(m_workingCityOverride.iID);
pStream->Write(NUM_YIELD_TYPES, m_aiYield);
pStream->Write(MAX_PLAYERS, m_aiCulture);
pStream->Write(MAX_PLAYERS, m_aiFoundValue);
pStream->Write(MAX_PLAYERS, m_aiPlayerCityRadiusCount);
pStream->Write(MAX_PLAYERS, m_aiPlotGroup);
pStream->Write(MAX_TEAMS, m_aiVisibilityCount);
pStream->Write(MAX_TEAMS, m_aiStolenVisibilityCount);
pStream->Write(MAX_TEAMS, m_aiRevealedOwner);
for(iI=0;iI<NUM_DIRECTION_TYPES;iI++)
{
pStream->Write((bool)m_abRiverCrossing[iI]);
}
for(iI=0;iI<MAX_TEAMS;iI++)
{
pStream->Write((bool)m_abRevealed[iI]);
}
pStream->Write(MAX_TEAMS, m_aeRevealedImprovementType);
pStream->Write(MAX_TEAMS, m_aeRevealedRouteType);
pStream->WriteString(m_szScriptData);
pStream->Write(GC.getNumBuildInfos(), m_paiBuildProgress);
for (iI=0;iI<MAX_PLAYERS;iI++)
{
pStream->Write(GC.getNumCultureLevelInfos(), m_apaiCultureRangeCities[iI]);
}
for (iI=0;iI<MAX_TEAMS;iI++)
{
pStream->Write(GC.getNumInvisibleInfos(), m_apaiInvisibleVisibilityCount[iI]);
}
m_units.Write(pStream);
}
void CvPlot::setLayoutDirty(bool bDirty)
{
if (!GC.IsGraphicsInitialized())
{
return;
}
if (isLayoutDirty() != bDirty)
{
m_bPlotLayoutDirty = bDirty;
if (isLayoutDirty() && (m_pPlotBuilder == NULL))
{
if (!updatePlotBuilder())
{
m_bPlotLayoutDirty = false;
}
}
}
}
bool CvPlot::updatePlotBuilder()
{
if (GC.IsGraphicsInitialized() && shouldUsePlotBuilder())
{
if (m_pPlotBuilder == NULL) // we need a plot builder... but it doesn't exist
{
m_pPlotBuilder = gDLL->getPlotBuilderIFace()->create();
gDLL->getPlotBuilderIFace()->init(m_pPlotBuilder, this);
}
return true;
}
return false;
}
bool CvPlot::isLayoutDirty() const
{
return m_bPlotLayoutDirty;
}
bool CvPlot::isLayoutStateDifferent() const
{
bool bSame = true;
// is worked
bSame &= m_bLayoutStateWorked == isBeingWorked();
// done
return !bSame;
}
void CvPlot::setLayoutStateToCurrent()
{
m_bLayoutStateWorked = isBeingWorked();
}
//------------------------------------------------------------------------------------------------
void CvPlot::getVisibleImprovementState(ImprovementTypes& eType, bool& bWorked)
{
eType = NO_IMPROVEMENT;
bWorked = false;
if (GC.getGameINLINE().getActiveTeam() == NO_TEAM)
{
return;
}
eType = getRevealedImprovementType(GC.getGameINLINE().getActiveTeam(), true);
if (eType == NO_IMPROVEMENT)
{
if (isActiveVisible(true))
{
if (isBeingWorked() && !isCity())
{
if (isWater())
{
eType = ((ImprovementTypes)(GC.getDefineINT("WATER_IMPROVEMENT")));
}
else
{
eType = ((ImprovementTypes)(GC.getDefineINT("LAND_IMPROVEMENT")));
}
}
}
}
// worked state
if (isActiveVisible(false) && isBeingWorked())
{
bWorked = true;
}
}
void CvPlot::getVisibleBonusState(BonusTypes& eType, bool& bImproved, bool& bWorked)
{
eType = NO_BONUS;
bImproved = false;
bWorked = false;
if (GC.getGameINLINE().getActiveTeam() == NO_TEAM)
{
return;
}
if (GC.getGameINLINE().isDebugMode())
{
eType = getBonusType();
}
else if (isRevealed(GC.getGameINLINE().getActiveTeam(), false))
{
eType = getBonusType(GC.getGameINLINE().getActiveTeam());
}
// improved and worked states ...
if (eType != NO_BONUS)
{
ImprovementTypes eRevealedImprovement = getRevealedImprovementType(GC.getGameINLINE().getActiveTeam(), true);
if ((eRevealedImprovement != NO_IMPROVEMENT) && GC.getImprovementInfo(eRevealedImprovement).isImprovementBonusTrade(eType))
{
bImproved = true;
bWorked = isBeingWorked();
}
}
}
bool CvPlot::shouldUsePlotBuilder()
{
bool bBonusImproved; bool bBonusWorked; bool bImprovementWorked;
BonusTypes eBonusType;
ImprovementTypes eImprovementType;
getVisibleBonusState(eBonusType, bBonusImproved, bBonusWorked);
getVisibleImprovementState(eImprovementType, bImprovementWorked);
if(eBonusType != NO_BONUS || eImprovementType != NO_IMPROVEMENT)
{
return true;
}
return false;
}
int CvPlot::calculateMaxYield(YieldTypes eYield) const
{
if (getTerrainType() == NO_TERRAIN)
{
return 0;
}
int iMaxYield = calculateNatureYield(eYield, NO_TEAM);
int iImprovementYield = 0;
for (int iImprovement = 0; iImprovement < GC.getNumImprovementInfos(); iImprovement++)
{
iImprovementYield = max(calculateImprovementYieldChange((ImprovementTypes)iImprovement, eYield, NO_PLAYER, true), iImprovementYield);
}
iMaxYield += iImprovementYield;
int iRouteYield = 0;
for (int iRoute = 0; iRoute < GC.getNumRouteInfos(); iRoute++)
{
iRouteYield = max(GC.getRouteInfo((RouteTypes)iRoute).getYieldChange(eYield), iRouteYield);
}
iMaxYield += iRouteYield;
if (isWater() && !isImpassable())
{
int iBuildingYield = 0;
for (int iBuilding = 0; iBuilding < GC.getNumBuildingInfos(); iBuilding++)
{
CvBuildingInfo& building = GC.getBuildingInfo((BuildingTypes)iBuilding);
iBuildingYield = max(building.getSeaPlotYieldChange(eYield) + building.getGlobalSeaPlotYieldChange(eYield), iBuildingYield);
}
iMaxYield += iBuildingYield;
}
int iExtraYieldThreshold = 0;
for (int iTrait = 0; iTrait < GC.getNumTraitInfos(); iTrait++)
{
CvTraitInfo& trait = GC.getTraitInfo((TraitTypes)iTrait);
iExtraYieldThreshold = max(trait.getExtraYieldThreshold(eYield), iExtraYieldThreshold);
}
if (iExtraYieldThreshold > 0 && iMaxYield > iExtraYieldThreshold)
{
iMaxYield += GC.getDefineINT("EXTRA_YIELD");
}
return iMaxYield;
}