void CvMap::calculateAreas() { PROFILE_FUNC(); CvPlot* pLoopPlot; CvArea* pArea; int iArea; int iI; for (iI = 0; iI < numPlotsINLINE(); iI++) { pLoopPlot = plotByIndexINLINE(iI); gDLL->callUpdater(); FAssertMsg(pLoopPlot != NULL, "LoopPlot is not assigned a valid value"); if (pLoopPlot->getArea() == FFreeList::INVALID_INDEX) { pArea = addArea(); pArea->init(pArea->getID(), pLoopPlot->isWater()); iArea = pArea->getID(); pLoopPlot->setArea(iArea); gDLL->getFAStarIFace()->GeneratePath(&GC.getAreaFinder(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), -1, -1, pLoopPlot->isWater(), iArea); } } }
//"Check plots for wetlands or seaWater. Returns true if found" bool CvMap::findWater(CvPlot* pPlot, int iRange, bool bFreshWater) { PROFILE_FUNC(); for (int iDX = -(iRange); iDX <= iRange; iDX++) { for (int iDY = -(iRange); iDY <= iRange; iDY++) { CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY); if (pLoopPlot != NULL) { if (bFreshWater) { if (pLoopPlot->isRiver()) { return true; } } else { if (pLoopPlot->isWater()) { return true; } } } } } return false; }
void CvMapGenerator::addLakes() { PROFILE_FUNC(); if (gDLL->getPythonIFace()->pythonAddLakes() && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { return; // Python override } gDLL->NiTextOut("Adding Lakes..."); CvPlot* pLoopPlot; int iI; for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++) { gDLL->callUpdater(); pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI); FAssertMsg(pLoopPlot != NULL, "LoopPlot is not assigned a valid value"); if (!(pLoopPlot->isWater())) { if (!(pLoopPlot->isCoastalLand())) { if (!(pLoopPlot->isRiver())) { if (GC.getGameINLINE().getMapRandNum(GC.getXMLval(XML_LAKE_PLOT_RAND), "addLakes") == 0) { pLoopPlot->setPlotType(PLOT_OCEAN); } } } } } }
/// Add in any temporary dominance zones from tactical AI void CvTacticalAnalysisMap::AddTemporaryZones() { CvTemporaryZone* pZone; CvTacticalAI* pTacticalAI = GET_PLAYER(m_ePlayer).GetTacticalAI(); if(pTacticalAI) { pTacticalAI->DropObsoleteZones(); pZone = pTacticalAI->GetFirstTemporaryZone(); while(pZone) { // Can't be a city zone (which is just used to boost priority but not establish a new zone) if(pZone->GetTargetType() != AI_TACTICAL_TARGET_CITY) { CvPlot* pPlot = GC.getMap().plot(pZone->GetX(), pZone->GetY()); if(pPlot) { CvTacticalDominanceZone newZone; newZone.SetDominanceZoneID(m_DominanceZones.size()); newZone.SetTerritoryType(TACTICAL_TERRITORY_TEMP_ZONE); newZone.SetOwner(NO_PLAYER); newZone.SetAreaID(pPlot->getArea()); newZone.SetWater(pPlot->isWater()); newZone.Extend(pPlot); newZone.SetNavalInvasion(pZone->IsNavalInvasion()); m_DominanceZones.push_back(newZone); } } pZone = pTacticalAI->GetNextTemporaryZone(); } } }
void CvMapGenerator::setPlotTypes(const int* paiPlotTypes) { CvPlot* pLoopPlot; int iNumPlots; iNumPlots = GC.getMapINLINE().numPlotsINLINE(); for (int iI = 0; iI < iNumPlots; iI++) { gDLL->callUpdater(); GC.getMapINLINE().plotByIndexINLINE(iI)->setPlotType(((PlotTypes)(paiPlotTypes[iI])), false, false); } GC.getMapINLINE().recalculateAreas(); for (int iI = 0; iI < iNumPlots; iI++) { gDLL->callUpdater(); pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI); if (pLoopPlot->isWater()) { if (pLoopPlot->isAdjacentToLand()) { pLoopPlot->setTerrainType(((TerrainTypes)(GC.getXMLval(XML_SHALLOW_WATER_TERRAIN))), false, false); } else { pLoopPlot->setTerrainType(((TerrainTypes)(GC.getXMLval(XML_DEEP_WATER_TERRAIN))), false, false); } } } }
CvPlot* CvArmyAI::DetectNearbyEnemy(PlayerTypes eEnemy, bool bNaval) { UnitHandle pUnit = GetFirstUnit(); while(pUnit) { for(int iDirectionLoop = 0; iDirectionLoop < NUM_DIRECTION_TYPES; ++iDirectionLoop) { CvPlot* pAdjacentPlot = plotDirection(pUnit->getX(), pUnit->getY(), ((DirectionTypes)iDirectionLoop)); if(pAdjacentPlot != NULL && pAdjacentPlot->isWater()==bNaval && pAdjacentPlot->getOwner() == eEnemy) { UnitHandle pOtherUnit = pAdjacentPlot->getBestDefender(eEnemy); if(pOtherUnit) { if(GC.getLogging() && GC.getAILogging()) { CvString strMsg; strMsg.Format("Ran into enemy unit during attack (x=%d y=%d). Need to declare war to continue!", pAdjacentPlot->getX(), pAdjacentPlot->getY()); GET_PLAYER(m_eOwner).getAIOperation(m_iOperationID)->LogOperationSpecialMessage(strMsg); } return pAdjacentPlot; } } } pUnit = GetNextUnit(); } return NULL; }
CvPlot* CvPlayerAI::FindBestMerchantTargetPlot(CvUnit* pGreatMerchant, bool bOnlySafePaths) { CvAssertMsg(pGreatMerchant, "pGreatMerchant is null"); if(!pGreatMerchant) { return NULL; } int iBestTurnsToReach = MAX_INT; CvPlot* pBestTargetPlot = NULL; int iPathTurns; UnitHandle pMerchant = UnitHandle(pGreatMerchant); CvTeam& kTeam = GET_TEAM(getTeam()); // Loop through each city state for(int iI = 0; iI < MAX_PLAYERS; iI++) { CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)iI); if(kPlayer.isMinorCiv()) { CvPlot* pCSPlot = kPlayer.getStartingPlot(); if(pCSPlot) { if(pCSPlot->isRevealed(getTeam())) { // Is this a minor we are friendly with? if(GetDiplomacyAI()->GetMinorCivApproach(kPlayer.GetID()) != MINOR_CIV_APPROACH_CONQUEST && !kTeam.isAtWar(kPlayer.getTeam()) && GetDiplomacyAI()->GetWarGoal(kPlayer.GetID()) == NO_WAR_GOAL_TYPE) { // Search all the plots adjacent to this city (since can't enter the minor city plot itself) for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++) { CvPlot* pAdjacentPlot = plotDirection(pCSPlot->getX(), pCSPlot->getY(), ((DirectionTypes)jJ)); if(pAdjacentPlot != NULL) { // Make sure this is still owned by the city state and is revealed to us and isn't a water tile if(pAdjacentPlot->getOwner() == (PlayerTypes)iI && pAdjacentPlot->isRevealed(getTeam()) && !pAdjacentPlot->isWater()) { iPathTurns = TurnsToReachTarget(pMerchant, pAdjacentPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/); if(iPathTurns < iBestTurnsToReach) { iBestTurnsToReach = iPathTurns; pBestTargetPlot = pAdjacentPlot; } } } } } } } } } return pBestTargetPlot; }
void CvMapGenerator::addGoodies() { PROFILE("CvMapGenerator::addGoodies"); if (gDLL->getPythonIFace()->callFunction(gDLL->getPythonIFace()->getMapScriptModule(), "addGoodies")) { if (!gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { return; // Python override } } gDLL->NiTextOut("Adding Goodies..."); if (GC.getEraInfo(GC.getGameINLINE().getStartEra()).isNoGoodies()) { return; } int iNumPlots = GC.getMapINLINE().numPlotsINLINE(); int* piShuffle = shuffle(iNumPlots, GC.getGameINLINE().getMapRand()); for (int iI = 0; iI < GC.getNumImprovementInfos(); iI++) { if (GC.getImprovementInfo((ImprovementTypes)iI).isGoody() && GC.getImprovementInfo((ImprovementTypes)iI).getTilesPerGoody() > 0) { for (int iJ = 0; iJ < iNumPlots; iJ++) { gDLL->callUpdater(); CvPlot *pPlot = GC.getMapINLINE().plotByIndexINLINE(piShuffle[iJ]); FAssertMsg(pPlot, "pPlot is expected not to be NULL"); if (!(pPlot->isWater())) { CvArea *pArea = GC.getMapINLINE().getArea(pPlot->getArea()); FAssertMsg(pArea, "pArea is expected not to be NULL"); if (pArea->getNumImprovements((ImprovementTypes)iI) < ((pArea->getNumTiles() + (GC.getImprovementInfo((ImprovementTypes)iI).getTilesPerGoody() / 2)) / GC.getImprovementInfo((ImprovementTypes) iI).getTilesPerGoody())) { if (canPlaceGoodyAt(((ImprovementTypes)iI), pPlot->getX_INLINE(), pPlot->getY_INLINE())) { pPlot->setImprovementType((ImprovementTypes)iI); } } } } } } SAFE_DELETE_ARRAY(piShuffle); }
void CvMapGenerator::addGoodies() { PROFILE_FUNC(); if (gDLL->getPythonIFace()->pythonAddGoodies() && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { return; // Python override } gDLL->NiTextOut("Adding Goodies..."); if (GC.getEraInfo(GC.getGameINLINE().getStartEra()).isNoGoodies()) { return; } int iNumPlots = GC.getMapINLINE().numPlotsINLINE(); std::vector<int> aiShuffle(iNumPlots); GC.getGameINLINE().getMapRand().shuffleSequence(aiShuffle, "addNonUniqueBonusType shuffle"); for (int iI = 0; iI < GC.getNumImprovementInfos(); iI++) { if (GC.getImprovementInfo((ImprovementTypes)iI).isGoody() && GC.getImprovementInfo((ImprovementTypes)iI).getTilesPerGoody() > 0) { for (int iJ = 0; iJ < iNumPlots; iJ++) { gDLL->callUpdater(); CvPlot *pPlot = GC.getMapINLINE().plotByIndexINLINE(aiShuffle[iJ]); FAssertMsg(pPlot, "pPlot is expected not to be NULL"); if (!(pPlot->isWater())) { CvArea *pArea = GC.getMapINLINE().getArea(pPlot->getArea()); FAssertMsg(pArea, "pArea is expected not to be NULL"); if (pArea->getNumImprovements((ImprovementTypes)iI) < ((pArea->getNumTiles() + (GC.getImprovementInfo((ImprovementTypes)iI).getTilesPerGoody() / 2)) / GC.getImprovementInfo((ImprovementTypes) iI).getTilesPerGoody())) { if (canPlaceGoodyAt(((ImprovementTypes)iI), pPlot->getX_INLINE(), pPlot->getY_INLINE())) { pPlot->setImprovementType((ImprovementTypes)iI); } } } } } } }
bool CvMapGenerator::canPlaceBonusAt(BonusTypes eBonus, int iX, int iY, bool bIgnoreLatitude) { PROFILE_FUNC(); CvArea* pArea; CvPlot* pPlot; CvPlot* pLoopPlot; int iRange; int iDX, iDY; int iI; pPlot = GC.getMapINLINE().plotINLINE(iX, iY); pArea = pPlot->area(); if (!(pPlot->canHaveBonus(eBonus, bIgnoreLatitude))) { return false; } long result = 0; if (gDLL->getPythonIFace()->pythonCanPlaceBonusAt(pPlot, &result) && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) // Python override { if (result >= 0) { return result; } else { FAssertMsg(false, "canPlaceBonusAt() must return >= 0"); } } for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pLoopPlot = plotDirection(iX, iY, ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if ((pLoopPlot->getBonusType() != NO_BONUS) && (pLoopPlot->getBonusType() != eBonus)) { return false; } } } CvBonusInfo& pInfo = GC.getBonusInfo(eBonus); if (pPlot->isWater()) { if (((GC.getMapINLINE().getNumBonusesOnLand(eBonus) * 100) / (GC.getMapINLINE().getNumBonuses(eBonus) + 1)) < pInfo.getMinLandPercent()) { return false; } } // Make sure there are none of the same bonus nearby: iRange = pInfo.getUniqueRange(); for (iDX = -(iRange); iDX <= iRange; iDX++) { for (iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(iX, iY, iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->area() == pArea) { if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange) { if (pLoopPlot->getBonusType() == eBonus) { return false; } } } } } } return true; }
// pStartPlot = the plot at whose SE corner the river is starting // void CvMapGenerator::doRiver(CvPlot *pStartPlot, CardinalDirectionTypes eLastCardinalDirection, CardinalDirectionTypes eOriginalCardinalDirection, int iThisRiverID) { if (iThisRiverID == -1) { iThisRiverID = GC.getMapINLINE().getNextRiverID(); GC.getMapINLINE().incrementNextRiverID(); } int iOtherRiverID = pStartPlot->getRiverID(); if (iOtherRiverID != -1 && iOtherRiverID != iThisRiverID) { return; // Another river already exists here; can't branch off of an existing river! } CvPlot *pRiverPlot = NULL; CvPlot *pAdjacentPlot = NULL; CardinalDirectionTypes eBestCardinalDirection = NO_CARDINALDIRECTION; if (eLastCardinalDirection==CARDINALDIRECTION_NORTH) { pRiverPlot = pStartPlot; if (pRiverPlot == NULL) { return; } pAdjacentPlot = plotCardinalDirection(pRiverPlot->getX_INLINE(), pRiverPlot->getY_INLINE(), CARDINALDIRECTION_EAST); if ((pAdjacentPlot == NULL) || pRiverPlot->isWOfRiver() || pRiverPlot->isWater() || pAdjacentPlot->isWater()) { return; } pStartPlot->setRiverID(iThisRiverID); pRiverPlot->setWOfRiver(true, eLastCardinalDirection); pRiverPlot = plotCardinalDirection(pRiverPlot->getX_INLINE(), pRiverPlot->getY_INLINE(), CARDINALDIRECTION_NORTH); } else if (eLastCardinalDirection==CARDINALDIRECTION_EAST) { pRiverPlot = plotCardinalDirection(pStartPlot->getX_INLINE(), pStartPlot->getY_INLINE(), CARDINALDIRECTION_EAST); if (pRiverPlot == NULL) { return; } pAdjacentPlot = plotCardinalDirection(pRiverPlot->getX_INLINE(), pRiverPlot->getY_INLINE(), CARDINALDIRECTION_SOUTH); if ((pAdjacentPlot == NULL) || pRiverPlot->isNOfRiver() || pRiverPlot->isWater() || pAdjacentPlot->isWater()) { return; } pStartPlot->setRiverID(iThisRiverID); pRiverPlot->setNOfRiver(true, eLastCardinalDirection); } else if (eLastCardinalDirection==CARDINALDIRECTION_SOUTH) { pRiverPlot = plotCardinalDirection(pStartPlot->getX_INLINE(), pStartPlot->getY_INLINE(), CARDINALDIRECTION_SOUTH); if (pRiverPlot == NULL) { return; } pAdjacentPlot = plotCardinalDirection(pRiverPlot->getX_INLINE(), pRiverPlot->getY_INLINE(), CARDINALDIRECTION_EAST); if ((pAdjacentPlot == NULL) || pRiverPlot->isWOfRiver() || pRiverPlot->isWater() || pAdjacentPlot->isWater()) { return; } pStartPlot->setRiverID(iThisRiverID); pRiverPlot->setWOfRiver(true, eLastCardinalDirection); } else if (eLastCardinalDirection==CARDINALDIRECTION_WEST) { pRiverPlot = pStartPlot; if (pRiverPlot == NULL) { return; } pAdjacentPlot = plotCardinalDirection(pRiverPlot->getX_INLINE(), pRiverPlot->getY_INLINE(), CARDINALDIRECTION_SOUTH); if ((pAdjacentPlot == NULL) || pRiverPlot->isNOfRiver() || pRiverPlot->isWater() || pAdjacentPlot->isWater()) { return; } pStartPlot->setRiverID(iThisRiverID); pRiverPlot->setNOfRiver(true, eLastCardinalDirection); pRiverPlot = plotCardinalDirection(pRiverPlot->getX_INLINE(), pRiverPlot->getY_INLINE(), CARDINALDIRECTION_WEST); } else { //FAssertMsg(false, "Illegal direction type"); // River is starting here, set the direction in the next step pRiverPlot = pStartPlot; long result = 0; if (gDLL->getPythonIFace()->pythonGetRiverStartCardinalDirection(pRiverPlot, &result) && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) // Python override { if (result >= 0) { eBestCardinalDirection = ((CardinalDirectionTypes)result); } else { FAssertMsg(false, "python pythonGetRiverStartCardinalDirection() must return >= 0"); } } } if (pRiverPlot == NULL) { return; // The river has flowed off the edge of the map. All is well. } else if (pRiverPlot->hasCoastAtSECorner()) { return; // The river has flowed into the ocean. All is well. } if (eBestCardinalDirection == NO_CARDINALDIRECTION) { int iBestValue = MAX_INT; for (int iI = 0; iI < NUM_CARDINALDIRECTION_TYPES; iI++) { if (getOppositeCardinalDirection((CardinalDirectionTypes)iI) != eOriginalCardinalDirection) { if (getOppositeCardinalDirection((CardinalDirectionTypes)iI) != eLastCardinalDirection) { CvPlot* pAdjacentPlot; pAdjacentPlot = plotCardinalDirection(pRiverPlot->getX_INLINE(), pRiverPlot->getY_INLINE(), ((CardinalDirectionTypes)iI)); if (pAdjacentPlot != NULL) { int iValue = getRiverValueAtPlot(pAdjacentPlot); if (iValue < iBestValue) { iBestValue = iValue; eBestCardinalDirection = (CardinalDirectionTypes)iI; } } } } } } if (eBestCardinalDirection != NO_CARDINALDIRECTION) { if (eOriginalCardinalDirection == NO_CARDINALDIRECTION) { eOriginalCardinalDirection = eBestCardinalDirection; } doRiver(pRiverPlot, eBestCardinalDirection, eOriginalCardinalDirection, iThisRiverID); } }
void CvMapGenerator::addRivers() { PROFILE_FUNC(); if (gDLL->getPythonIFace()->pythonAddRivers() && !gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { return; // Python override } gDLL->NiTextOut("Adding Rivers..."); CvPlot* pLoopPlot; CvPlot* pStartPlot; int iPass; int iRiverSourceRange; int iSeaWaterRange; int iI; for (iPass = 0; iPass < 4; iPass++) { if (iPass <= 1) { iRiverSourceRange = GC.getXMLval(XML_RIVER_SOURCE_MIN_RIVER_RANGE); } else { iRiverSourceRange = (GC.getXMLval(XML_RIVER_SOURCE_MIN_RIVER_RANGE) / 2); } if (iPass <= 1) { iSeaWaterRange = GC.getXMLval(XML_RIVER_SOURCE_MIN_SEAWATER_RANGE); } else { iSeaWaterRange = (GC.getXMLval(XML_RIVER_SOURCE_MIN_SEAWATER_RANGE) / 2); } for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++) { gDLL->callUpdater(); pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI); FAssertMsg(pLoopPlot != NULL, "LoopPlot is not assigned a valid value"); if (!(pLoopPlot->isWater())) { if (((iPass == 0) && (pLoopPlot->isHills() || pLoopPlot->isPeak())) || ((iPass == 1) && !(pLoopPlot->isCoastalLand()) && (GC.getGameINLINE().getMapRandNum(8, "addRivers") == 0)) || ((iPass == 2) && (pLoopPlot->isHills() || pLoopPlot->isPeak()) && (pLoopPlot->area()->getNumRiverEdges() < ((pLoopPlot->area()->getNumTiles() / GC.getXMLval(XML_PLOTS_PER_RIVER_EDGE)) + 1))) || ((iPass == 3) && (pLoopPlot->area()->getNumRiverEdges() < ((pLoopPlot->area()->getNumTiles() / GC.getXMLval(XML_PLOTS_PER_RIVER_EDGE)) + 1)))) { if (!(GC.getMapINLINE().findWater(pLoopPlot, iRiverSourceRange, true))) { if (!(GC.getMapINLINE().findWater(pLoopPlot, iSeaWaterRange, false))) { pStartPlot = pLoopPlot->getInlandCorner(); if (pStartPlot != NULL) { doRiver(pStartPlot); } } } } } } } }
bool CvMapGenerator::canPlaceBonusAt(BonusTypes eBonus, int iX, int iY, bool bIgnoreLatitude) { PROFILE_FUNC(); CvArea* pArea; CvPlot* pPlot; CvPlot* pLoopPlot; int iRange; int iDX, iDY; int iI; pPlot = GC.getMapINLINE().plotINLINE(iX, iY); pArea = pPlot->area(); if (!(pPlot->canHaveBonus(eBonus, bIgnoreLatitude))) { return false; } long result = 0; CyPlot kPlot = CyPlot(pPlot); CyArgsList argsList; argsList.add(gDLL->getPythonIFace()->makePythonObject(&kPlot)); if (gDLL->getPythonIFace()->callFunction(gDLL->getPythonIFace()->getMapScriptModule(), "canPlaceBonusAt", argsList.makeFunctionArgs(), &result)) { if (!gDLL->getPythonIFace()->pythonUsingDefaultImpl()) { if (result >= 0) { return result; } else { FAssertMsg(false, "canPlaceBonusAt() must return >= 0"); } } } for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { pLoopPlot = plotDirection(iX, iY, ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if ((pLoopPlot->getBonusType() != NO_BONUS) && (pLoopPlot->getBonusType() != eBonus)) { return false; } } } CvBonusInfo& pInfo = GC.getBonusInfo(eBonus); CvBonusClassInfo& pClassInfo = GC.getBonusClassInfo((BonusClassTypes) pInfo.getBonusClassType()); if (pPlot->isWater()) { if (((GC.getMapINLINE().getNumBonusesOnLand(eBonus) * 100) / (GC.getMapINLINE().getNumBonuses(eBonus) + 1)) < pInfo.getMinLandPercent()) { return false; } } // Make sure there are no bonuses of the same class (but a different type) nearby: iRange = pClassInfo.getUniqueRange(); for (iDX = -(iRange); iDX <= iRange; iDX++) { for (iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(iX, iY, iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->area() == pArea) { if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange) { BonusTypes eOtherBonus = pLoopPlot->getBonusType(); if (eOtherBonus != NO_BONUS) { if (GC.getBonusInfo(eOtherBonus).getBonusClassType() == pInfo.getBonusClassType()) { return false; } } } } } } } // Make sure there are none of the same bonus nearby: iRange = pInfo.getUniqueRange(); for (iDX = -(iRange); iDX <= iRange; iDX++) { for (iDY = -(iRange); iDY <= iRange; iDY++) { pLoopPlot = plotXY(iX, iY, iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->area() == pArea) { if (plotDistance(iX, iY, pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) <= iRange) { if (pLoopPlot->getBonusType() == eBonus) { return false; } } } } } } return true; }
/// Get center of mass of units in army (account for world wrap!) CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired) { CvPlot* pRtnValue = NULL; int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; UnitHandle pUnit; int iReferenceUnitX = -1; int iWorldWidth = GC.getMap().getGridWidth(); pUnit = GetFirstUnit(); if(pUnit) { iReferenceUnitX = pUnit->getX(); } while(pUnit) { int iUnitX = pUnit->getX(); bool bWorldWrapAdjust = false; int iDiff = iUnitX - iReferenceUnitX; if(abs(iDiff) > (iWorldWidth / 2)) { bWorldWrapAdjust = true; } if(bWorldWrapAdjust) { iTotalX += iUnitX + iWorldWidth; } else { iTotalX += iUnitX; } iTotalY += pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); } if(iNumUnits > 0) { int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits; if(iAverageX >= iWorldWidth) { iAverageX = iAverageX - iWorldWidth; } int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits; pRtnValue = GC.getMap().plot(iAverageX, iAverageY); } // Domain check if (eDomainRequired != NO_DOMAIN && pRtnValue) { if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA) { // Find an adjacent plot that works for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } // Try two plots out if really having problems for (int iDX = -2; iDX <= 2; iDX++) { for (int iDY = -2; iDY <= 2; iDY++) { CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2); if (pLoopPlot) { if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } } } // Give up - just use location of first unit pUnit = GetFirstUnit(); pRtnValue = pUnit->plot(); } } return pRtnValue; }
/// Get center of mass of units in army (account for world wrap!) CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired) { CvPlot* pRtnValue = NULL; int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; UnitHandle pUnit; int iReferenceUnitX = -1; int iWorldWidth = GC.getMap().getGridWidth(); pUnit = GetFirstUnit(); if(pUnit) { iReferenceUnitX = pUnit->getX(); } while(pUnit) { int iUnitX = pUnit->getX(); bool bWorldWrapAdjust = false; int iDiff = iUnitX - iReferenceUnitX; if(abs(iDiff) > (iWorldWidth / 2)) { bWorldWrapAdjust = true; } if(bWorldWrapAdjust) { iTotalX += iUnitX + iWorldWidth; } else { iTotalX += iUnitX; } iTotalY += pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); } if(iNumUnits > 0) { int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits; if(iAverageX >= iWorldWidth) { iAverageX = iAverageX - iWorldWidth; } int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits; pRtnValue = GC.getMap().plot(iAverageX, iAverageY); } // Domain check if (eDomainRequired != NO_DOMAIN && pRtnValue) { if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA) { // Find an adjacent plot that works for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } // Try two plots out if really having problems #ifdef AUI_HEXSPACE_DX_LOOPS int iMaxDX, iDX; CvPlot* pLoopPlot; for (int iDY = -2; iDY <= 2; iDY++) { iMaxDX = 2 - MAX(0, iDY); for (iDX = -2 - MIN(0, iDY); iDX <= iMaxDX; iDX++) // MIN() and MAX() stuff is to reduce loops (hexspace!) { // No need for range check because loops are set up properly pLoopPlot = plotXY(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY); if (pLoopPlot) { if (hexDistance(iDX, iDY) == 2) #else for (int iDX = -2; iDX <= 2; iDX++) { for (int iDY = -2; iDY <= 2; iDY++) { CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2); if (pLoopPlot) { #ifdef AUI_FIX_HEX_DISTANCE_INSTEAD_OF_PLOT_DISTANCE if (hexDistance(iDX, iDY) == 2) #else if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2) #endif #endif { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } } } // Give up - just use location of first unit pUnit = GetFirstUnit(); pRtnValue = pUnit->plot(); } } return pRtnValue; } /// Return distance from this plot of unit in army farthest away int CvArmyAI::GetFurthestUnitDistance(CvPlot* pPlot) { int iLargestDistance = 0; UnitHandle pUnit; int iNewDistance; pUnit = GetFirstUnit(); while(pUnit) { iNewDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY()); if(iNewDistance > iLargestDistance) { iLargestDistance = iNewDistance; } pUnit = GetNextUnit(); } return iLargestDistance; } // FORMATION ACCESSORS /// Retrieve index of the formation used by this army int CvArmyAI::GetFormationIndex() const { return m_iFormationIndex; } /// Set index of the formation used by this army void CvArmyAI::SetFormationIndex(int iFormationIndex) { CvArmyFormationSlot slot; if(m_iFormationIndex != iFormationIndex) { m_iFormationIndex = iFormationIndex; CvMultiUnitFormationInfo* thisFormation = GC.getMultiUnitFormationInfo(m_iFormationIndex); if(thisFormation) { int iNumSlots = thisFormation->getNumFormationSlotEntries(); // Build all the formation entries m_FormationEntries.clear(); for(int iI = 0; iI < iNumSlots; iI++) { slot.SetUnitID(ARMY_NO_UNIT); slot.SetTurnAtCheckpoint(ARMYSLOT_UNKNOWN_TURN_AT_CHECKPOINT); m_FormationEntries.push_back(slot); } } } } /// How many slots are there in this formation if filled int CvArmyAI::GetNumFormationEntries() const { return m_FormationEntries.size(); } /// How many slots do we currently have filled? int CvArmyAI::GetNumSlotsFilled() const { int iRtnValue = 0; for(unsigned int iI = 0; iI < m_FormationEntries.size(); iI++) { if(m_FormationEntries[iI].m_iUnitID != ARMY_NO_UNIT) { iRtnValue++; } } return iRtnValue; }
/// Get center of mass of units in army (account for world wrap!) CvPlot* CvArmyAI::GetCenterOfMass(DomainTypes eDomainRequired) { int iTotalX = 0; int iTotalY = 0; int iNumUnits = 0; #if defined(MOD_BALANCE_CORE) UnitHandle pUnit = GetFirstUnit(); if (!pUnit) return NULL; int iTotalX2 = 0; int iTotalY2 = 0; int iWorldWidth = GC.getMap().getGridWidth(); int iWorldHeight = GC.getMap().getGridHeight(); //the first unit is our reference ... int iRefX = pUnit->getX(); int iRefY = pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); while(pUnit) { int iDX = pUnit->getX() - iRefX; int iDY = pUnit->getY() - iRefY; if (GC.getMap().isWrapX()) { if( iDX > +(iWorldWidth / 2)) iDX -= iWorldWidth; if( iDX < -(iWorldWidth / 2)) iDX += iWorldWidth; } if (GC.getMap().isWrapY()) { if( iDY > +(iWorldHeight / 2)) iDY -= iWorldHeight; if( iDY < -(iWorldHeight / 2)) iDY += iWorldHeight; } iTotalX += iDX; iTotalY += iDY; iTotalX2 += iDX*iDX; iTotalY2 += iDY*iDY; iNumUnits++; pUnit = GetNextUnit(); } if (iNumUnits==0) return NULL; //this is for debugging float fVarX = (iTotalX2 / (float)iNumUnits) - (iTotalX/(float)iNumUnits)*(iTotalX/(float)iNumUnits); float fVarY = (iTotalY2 / (float)iNumUnits) - (iTotalY/(float)iNumUnits)*(iTotalY/(float)iNumUnits); //finally, compute average (with rounding) int iAvgX = (iTotalX + (iNumUnits / 2)) / iNumUnits + iRefX; int iAvgY = (iTotalY + (iNumUnits / 2)) / iNumUnits + iRefY; if (fVarX > 64 || fVarY > 64) { CvString msg = CvString::format("Warning: Army %d with %d units Center of Mass (%d,%d) has a large variance (%.2f,%.2f)\n", GetID(), iNumUnits, iAvgX, iAvgY, fVarX, fVarY); OutputDebugString( msg.c_str() ); } //this handles wrapped coordinates CvPlot* pCOM = GC.getMap().plot(iAvgX, iAvgY); if (!pCOM) return NULL; //don't return it directly but use the plot of the closest unit pUnit = GetFirstUnit(); std::vector<SPlotWithScore> vPlots; while (pUnit) { if (eDomainRequired == NO_DOMAIN || pUnit->plot()->getDomain()==eDomainRequired) vPlots.push_back( SPlotWithScore(pUnit->plot(),plotDistance(*pUnit->plot(),*pCOM)) ); pUnit = GetNextUnit(); } if (vPlots.empty()) return NULL; //this sorts ascending! std::sort(vPlots.begin(),vPlots.end()); return vPlots.front().pPlot; #else CvPlot* pRtnValue = NULL; UnitHandle pUnit; int iReferenceUnitX = -1; int iWorldWidth = GC.getMap().getGridWidth(); pUnit = GetFirstUnit(); if(pUnit) { iReferenceUnitX = pUnit->getX(); } while(pUnit) { int iUnitX = pUnit->getX(); bool bWorldWrapAdjust = false; int iDiff = iUnitX - iReferenceUnitX; if(abs(iDiff) > (iWorldWidth / 2)) { bWorldWrapAdjust = true; } if(bWorldWrapAdjust) { iTotalX += iUnitX + iWorldWidth; } else { iTotalX += iUnitX; } iTotalY += pUnit->getY(); iNumUnits++; pUnit = GetNextUnit(); } if(iNumUnits > 0) { int iAverageX = (iTotalX + (iNumUnits / 2)) / iNumUnits; if(iAverageX >= iWorldWidth) { iAverageX = iAverageX - iWorldWidth; } int iAverageY = (iTotalY + (iNumUnits / 2)) / iNumUnits; pRtnValue = GC.getMap().plot(iAverageX, iAverageY); } // Domain check if (eDomainRequired != NO_DOMAIN && pRtnValue) { if (pRtnValue->isWater() && eDomainRequired == DOMAIN_LAND || !pRtnValue->isWater() && eDomainRequired == DOMAIN_SEA) { // Find an adjacent plot that works for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++) { CvPlot *pLoopPlot = plotDirection(pRtnValue->getX(), pRtnValue->getY(), ((DirectionTypes)iI)); if (pLoopPlot != NULL) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } // Try two plots out if really having problems for (int iDX = -2; iDX <= 2; iDX++) { for (int iDY = -2; iDY <= 2; iDY++) { CvPlot *pLoopPlot = plotXYWithRangeCheck(pRtnValue->getX(), pRtnValue->getY(), iDX, iDY, 2); if (pLoopPlot) { if (plotDistance(pRtnValue->getX(), pRtnValue->getY(), pLoopPlot->getX(), pLoopPlot->getY()) == 2) { if (pLoopPlot->isWater() && eDomainRequired == DOMAIN_SEA || !pLoopPlot->isWater() && eDomainRequired == DOMAIN_LAND) { return pLoopPlot; } } } } } // Give up - just use location of first unit pUnit = GetFirstUnit(); pRtnValue = pUnit->plot(); } } return pRtnValue; #endif }
/// Add data for this cell into dominance zone information void CvTacticalAnalysisMap::AddToDominanceZones(int iIndex, CvTacticalAnalysisCell* pCell) { CvPlot* pPlot = GC.getMap().plotByIndex(iIndex); // Compute zone data for this cell m_TempZone.SetAreaID(pPlot->getArea()); m_TempZone.SetOwner(pPlot->getOwner()); m_TempZone.SetWater(pPlot->isWater()); if(!pPlot->isOwned()) { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_NO_OWNER); } else if(pPlot->getTeam() == m_pPlayer->getTeam()) { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_FRIENDLY); } else if(GET_TEAM(m_pPlayer->getTeam()).isAtWar(pPlot->getTeam())) { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_ENEMY); } else { m_TempZone.SetTerritoryType(TACTICAL_TERRITORY_NEUTRAL); } m_TempZone.SetClosestCity(NULL); if(m_TempZone.GetTerritoryType() == TACTICAL_TERRITORY_ENEMY || m_TempZone.GetTerritoryType() == TACTICAL_TERRITORY_NEUTRAL || m_TempZone.GetTerritoryType() == TACTICAL_TERRITORY_FRIENDLY) { int iLoop; int iBestDistance = MAX_INT; CvCity* pBestCity = NULL; for(CvCity* pLoopCity = GET_PLAYER(m_TempZone.GetOwner()).firstCity(&iLoop); pLoopCity != NULL; pLoopCity = GET_PLAYER(m_TempZone.GetOwner()).nextCity(&iLoop)) { int iDistance = plotDistance(pLoopCity->getX(), pLoopCity->getY(), pPlot->getX(), pPlot->getY()); if(iDistance < iBestDistance) { iBestDistance = iDistance; pBestCity = pLoopCity; } } if(pBestCity != NULL) { m_TempZone.SetClosestCity(pBestCity); } } // Now see if we already have a matching zone CvTacticalDominanceZone* pZone = FindExistingZone(pPlot); if(!pZone) { // Data populated, now add to vector m_TempZone.SetDominanceZoneID(m_DominanceZones.size()); m_DominanceZones.push_back(m_TempZone); pZone = &m_DominanceZones[m_DominanceZones.size() - 1]; } // If this isn't owned territory, update zone with military strength info if(pZone->GetTerritoryType() == TACTICAL_TERRITORY_NO_OWNER || pZone->GetTerritoryType() == TACTICAL_TERRITORY_TEMP_ZONE) { CvUnit* pFriendlyUnit = pCell->GetFriendlyMilitaryUnit(); if(pFriendlyUnit) { if(pFriendlyUnit->getDomainType() == DOMAIN_AIR || (pFriendlyUnit->getDomainType() == DOMAIN_LAND && !pZone->IsWater()) || (pFriendlyUnit->getDomainType() == DOMAIN_SEA && pZone->IsWater())) { int iStrength = pFriendlyUnit->GetBaseCombatStrengthConsideringDamage(); if(iStrength == 0 && pFriendlyUnit->isEmbarked() && !pZone->IsWater()) { iStrength = pFriendlyUnit->GetBaseCombatStrength(true); } pZone->AddFriendlyStrength(iStrength * m_iUnitStrengthMultiplier); pZone->AddFriendlyRangedStrength(pFriendlyUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true)); if(pFriendlyUnit->GetRange() > GetBestFriendlyRange()) { SetBestFriendlyRange(pFriendlyUnit->GetRange()); } if(pFriendlyUnit->IsRangeAttackIgnoreLOS()) { SetIgnoreLOS(true); } pZone->AddFriendlyUnitCount(1); if(pFriendlyUnit->isRanged()) { pZone->AddFriendlyRangedUnitCount(1); } } } CvUnit* pEnemyUnit = pCell->GetEnemyMilitaryUnit(); if(pEnemyUnit) { if(pEnemyUnit->getDomainType() == DOMAIN_AIR || (pEnemyUnit->getDomainType() == DOMAIN_LAND && !pZone->IsWater()) || (pEnemyUnit->getDomainType() == DOMAIN_SEA && pZone->IsWater())) { int iStrength = pEnemyUnit->GetBaseCombatStrengthConsideringDamage(); if(iStrength == 0 && pEnemyUnit->isEmbarked() && !pZone->IsWater()) { iStrength = pEnemyUnit->GetBaseCombatStrength(true); } #if defined(MOD_AI_SMART_V3) int iEnemyRangedStrength = pEnemyUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true); if (MOD_AI_SMART_V3) { if (!pCell->IsVisible()) { iStrength /= 2; iEnemyRangedStrength /= 2; } iEnemyRangedStrength = iEnemyRangedStrength * m_iUnitStrengthMultiplier; } #endif pZone->AddEnemyStrength(iStrength * m_iUnitStrengthMultiplier); #if defined(MOD_AI_SMART_V3) pZone->AddEnemyRangedStrength(iEnemyRangedStrength); #else pZone->AddEnemyRangedStrength(pEnemyUnit->GetMaxRangedCombatStrength(NULL, /*pCity*/ NULL, true, true)); #endif pZone->AddEnemyUnitCount(1); if(pEnemyUnit->isRanged()) { pZone->AddEnemyRangedUnitCount(1); } if (pEnemyUnit->getDomainType() == DOMAIN_SEA) { pZone->AddEnemyNavalUnitCount(1); } } } } // Set zone for this cell pCell->SetDominanceZone(pZone->GetDominanceZoneID()); }
///TKs Med TradeScreens void CvMapGenerator::addEurope() { PROFILE_FUNC(); gDLL->NiTextOut("Adding Europe..."); for (int iEurope = 0; iEurope < GC.getNumEuropeInfos(); ++iEurope) { EuropeTypes eEurope = (EuropeTypes) iEurope; CvEuropeInfo& kEurope = GC.getEuropeInfo(eEurope); int iWidthPercent = kEurope.getWidthPercent(); gDLL->getPythonIFace()->pythonGetEuropeWidthPercent(eEurope, &iWidthPercent); int iMinLandDistance = kEurope.getMinLandDistance(); gDLL->getPythonIFace()->pythonGetEuropeMinLandDistance(eEurope, &iMinLandDistance); //try several times until at least one start europe is found //bool bWaterRoute = (kEurope.getDomainsValid(DOMAIN_SEA)); bool bAnyEuropeFound = false; bool bCheckDirection = true; //int iDomainCount = 0; int iGridWidth = GC.getMapINLINE().getGridWidthINLINE(); int iGridHeight = GC.getMapINLINE().getGridHeightINLINE(); for ( ; iMinLandDistance >= 0 && !bAnyEuropeFound; iMinLandDistance--) { for (int i = 0; i < GC.getMapINLINE().numPlotsINLINE(); ++i) { CvPlot* pPlot = GC.getMapINLINE().plotByIndexINLINE(i); bCheckDirection = true; if (!kEurope.getDomainsValid(DOMAIN_SEA) && pPlot->isWater()) { bCheckDirection = false; } //else if (kEurope.getDomainsValid(DOMAIN_SEA)) //{ //iDomainCount++; //} if (!kEurope.getDomainsValid(DOMAIN_LAND) && !pPlot->isWater()) { bCheckDirection = false; } //else if (kEurope.getDomainsValid(DOMAIN_LAND)) //{ //iDomainCount++; //} if (bCheckDirection && !pPlot->isTradeScreenAccessPlot(eEurope)) { for (int iDir = 0; iDir < NUM_DIRECTION_TYPES; ++iDir) { /*DIRECTION_NORTH, DIRECTION_NORTHEAST, DIRECTION_EAST, DIRECTION_SOUTHEAST, DIRECTION_SOUTH, DIRECTION_SOUTHWEST, DIRECTION_WEST, DIRECTION_NORTHWEST,*/ bool bEurope = false; if (kEurope.getDirectionValid(iDir)) { switch ((DirectionTypes)iDir) { case DIRECTION_EAST: bEurope = (pPlot->getX_INLINE() > (100 - iWidthPercent) * iGridWidth / 100 && pPlot->getY_INLINE() <= (100 - iWidthPercent) * iGridHeight / 100 && pPlot->getY_INLINE() >= iWidthPercent * iGridHeight / 100); break; case DIRECTION_NORTHEAST: bEurope = (pPlot->getX_INLINE() > (100 - iWidthPercent) * iGridWidth / 100 && pPlot->getY_INLINE() > (100 - iWidthPercent) * iGridHeight / 100); break; case DIRECTION_SOUTHEAST: bEurope = (pPlot->getX_INLINE() > (100 - iWidthPercent) * iGridWidth / 100 && pPlot->getY_INLINE() < iWidthPercent * iGridHeight / 100); break; case DIRECTION_WEST: bEurope = (pPlot->getX_INLINE() < iWidthPercent * iGridWidth / 100 && pPlot->getY_INLINE() <= (100 - iWidthPercent) * iGridHeight / 100 && pPlot->getY_INLINE() >= iWidthPercent * iGridHeight / 100); break; case DIRECTION_NORTHWEST: bEurope = (pPlot->getX_INLINE() < (100 - iWidthPercent) * iGridWidth / 100 && pPlot->getY_INLINE() > (100 - iWidthPercent) * iGridHeight / 100); break; case DIRECTION_SOUTHWEST: bEurope = (pPlot->getX_INLINE() < (100 - iWidthPercent) * iGridWidth / 100 && pPlot->getY_INLINE() < iWidthPercent * iGridHeight / 100); break; case DIRECTION_NORTH: bEurope = (pPlot->getY_INLINE() > (100 - iWidthPercent) * iGridHeight / 100 && pPlot->getX_INLINE() > iWidthPercent * iGridWidth / 100 && pPlot->getX_INLINE() < (100 - iWidthPercent) * iGridWidth / 100); break; case DIRECTION_SOUTH: bEurope = (pPlot->getY_INLINE() < iWidthPercent * iGridHeight / 100 && pPlot->getX_INLINE() > iWidthPercent * iGridWidth / 100 && pPlot->getX_INLINE() < (100 - iWidthPercent) * iGridWidth / 100); break; default: FAssertMsg(false, "Invalid direction"); break; } } if (bEurope) { if (kEurope.getDomainsValid(DOMAIN_SEA)) { for (int i = -iMinLandDistance; i <= iMinLandDistance && bEurope; i++) { for (int j = -iMinLandDistance; j <= iMinLandDistance && bEurope; j++) { CvPlot* pLoopPlot = ::plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), i, j); if (pLoopPlot != NULL) { if (!pLoopPlot->isWater()) { bEurope = false; } } } } if (bEurope) { if (pPlot->getFeatureType() != NO_FEATURE && GC.getFeatureInfo(pPlot->getFeatureType()).isImpassable()) { pPlot->setFeatureType(NO_FEATURE); } if (pPlot->isImpassable()) { bEurope = false; } } if (bEurope) { if (!pPlot->isEurope()) { pPlot->setEurope(eEurope); } pPlot->setTradeScreenAccess(eEurope); bAnyEuropeFound = true; } bEurope = true; } if (kEurope.getDomainsValid(DOMAIN_LAND)) { switch ((DirectionTypes)iDir) { case DIRECTION_EAST: if (pPlot->getX_INLINE() < (iGridWidth - kEurope.getMaxLandCoverage())) { bEurope = false; } break; case DIRECTION_NORTHEAST: if (pPlot->getX_INLINE() < (iGridWidth - kEurope.getMaxLandCoverage()) && pPlot->getY_INLINE() < (iGridHeight - kEurope.getMaxLandCoverage())) { bEurope = false; } break; case DIRECTION_SOUTHEAST: if (pPlot->getY_INLINE() > kEurope.getMaxLandCoverage() && pPlot->getX_INLINE() < (iGridWidth - kEurope.getMaxLandCoverage())) { bEurope = false; } break; case DIRECTION_WEST: if (pPlot->getX_INLINE() > kEurope.getMaxLandCoverage()) { bEurope = false; } break; case DIRECTION_NORTHWEST: if (pPlot->getX_INLINE() > kEurope.getMaxLandCoverage() && pPlot->getY_INLINE() < (iGridHeight - kEurope.getMaxLandCoverage())) { bEurope = false; } break; case DIRECTION_SOUTHWEST: if (pPlot->getY_INLINE() > kEurope.getMaxLandCoverage() && pPlot->getX_INLINE() > kEurope.getMaxLandCoverage()) { bEurope = false; } break; case DIRECTION_NORTH: if (pPlot->getY_INLINE() < (iGridHeight - kEurope.getMaxLandCoverage())) { bEurope = false; } break; case DIRECTION_SOUTH: if (pPlot->getY_INLINE() > kEurope.getMaxLandCoverage()) { bEurope = false; } break; default: FAssertMsg(false, "Invalid direction"); break; } if (bEurope) { if (pPlot->getFeatureType() != NO_FEATURE && GC.getFeatureInfo(pPlot->getFeatureType()).isImpassable()) { pPlot->setFeatureType(NO_FEATURE); } if (pPlot->isImpassable()) { bEurope = false; } } if (bEurope) { if (!pPlot->isEurope()) { pPlot->setEurope(eEurope); } pPlot->setTradeScreenAccess(eEurope); bAnyEuropeFound = true; } } } /*if (bEurope) { if (pPlot->getFeatureType() != NO_FEATURE && GC.getFeatureInfo(pPlot->getFeatureType()).isImpassable()) { pPlot->setFeatureType(NO_FEATURE); } if (pPlot->isImpassable()) { bEurope = false; } } if (bEurope) { if (!pPlot->isEurope()) { pPlot->setEurope(eEurope); } pPlot->setTradeScreenAccess(eEurope); bAnyEuropeFound = true; }*/ } } } } } }
///Tks Med CvPlot* CvMap::syncRandPlot(int iFlags, int iArea, int iMinUnitDistance, int iTimeout, bool bIgnoreNativeTeams) { ///TKe CvPlot* pPlot = NULL; int iCount = 0; while (iCount < iTimeout) { CvPlot* pTestPlot = plotSorenINLINE(GC.getGameINLINE().getSorenRandNum(getGridWidthINLINE(), "Rand Plot Width"), GC.getGameINLINE().getSorenRandNum(getGridHeightINLINE(), "Rand Plot Height")); FAssertMsg(pTestPlot != NULL, "TestPlot is not assigned a valid value"); if ((iArea == -1) || (pTestPlot->getArea() == iArea)) { bool bValid = true; if (bValid) { if (iMinUnitDistance != -1) { for (int iDX = -(iMinUnitDistance); iDX <= iMinUnitDistance; iDX++) { for (int iDY = -(iMinUnitDistance); iDY <= iMinUnitDistance; iDY++) { CvPlot* pLoopPlot = plotXY(pTestPlot->getX_INLINE(), pTestPlot->getY_INLINE(), iDX, iDY); if (pLoopPlot != NULL) { if (pLoopPlot->isUnit()) { bValid = false; } } } } } } if (bValid) { if (iFlags & RANDPLOT_LAND) { if (pTestPlot->isWater()) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_UNOWNED) { if (pTestPlot->isOwned()) { ///Tks Med if (bIgnoreNativeTeams) { if (!GET_PLAYER(pTestPlot->getOwnerINLINE()).isNative()) { bValid = false; } } else { bValid = false; } ///TKe } } } if (bValid) { if (iFlags & RANDPLOT_ADJACENT_UNOWNED) { if (pTestPlot->isAdjacentOwned()) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_ADJACENT_LAND) { if (!(pTestPlot->isAdjacentToLand())) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_PASSIBLE) { if (pTestPlot->isImpassable()) { bValid = false; } } } if (bValid) { if (iFlags & RANDPLOT_NOT_VISIBLE_TO_CIV) { ///TKs Med if (pTestPlot->isVisibleToCivTeam(bIgnoreNativeTeams)) { bValid = false; } ///TKe } } ///TKs Med if (bValid) { if (bIgnoreNativeTeams) { if (pTestPlot->isVisibleToWatchingHuman()) { bValid = false; } } } ///TKe if (bValid) { if (iFlags & RANDPLOT_NOT_CITY) { if (pTestPlot->isCity()) { bValid = false; } } } if (bValid) { pPlot = pTestPlot; break; } } iCount++; } return pPlot; }
/// Add data for this cell into dominance zone information void CvTacticalAnalysisMap::AddToDominanceZones(int iIndex, CvTacticalAnalysisCell* pCell) { TeamTypes ourTeam = GET_PLAYER(m_ePlayer).getTeam(); CvPlot* pPlot = GC.getMap().plotByIndex(iIndex); // Compute zone data for this cell CvTacticalDominanceZone newZone; newZone.SetAreaID(pPlot->getArea()); newZone.SetWater(pPlot->isWater()); int iCityDistance = GC.getGame().GetClosestCityDistanceInTurns(pPlot); CvCity* pCity = GC.getGame().GetClosestCityByEstimatedTurns(pPlot); PlayerTypes eOwnerPlayer = NO_PLAYER; TeamTypes eOwnerTeam = NO_TEAM; //for plots far away from a city, check the owner if (iCityDistance>2) { eOwnerTeam = pPlot->getTeam(); eOwnerPlayer = pPlot->getOwner(); //there is almost always a closest city, but we're not always interested if (pCity && eOwnerPlayer!=pCity->getOwner()) pCity = NULL; } else if (pCity) //look at the city { eOwnerTeam = pCity->getTeam(); eOwnerPlayer = pCity->getOwner(); } newZone.SetOwner(eOwnerPlayer); newZone.SetZoneCity(pCity); newZone.Extend(pPlot); if(eOwnerTeam==NO_TEAM) { newZone.SetTerritoryType(TACTICAL_TERRITORY_NO_OWNER); } else if(eOwnerTeam == ourTeam) { newZone.SetTerritoryType(TACTICAL_TERRITORY_FRIENDLY); } else if(GET_TEAM(ourTeam).isAtWar(eOwnerTeam)) { newZone.SetTerritoryType(TACTICAL_TERRITORY_ENEMY); } else { newZone.SetTerritoryType(TACTICAL_TERRITORY_NEUTRAL); } // Now see if we already have a matching zone CvTacticalDominanceZone* pZone = MergeWithExistingZone(&newZone); if(!pZone) { // Data populated, now add to vector newZone.SetDominanceZoneID(m_DominanceZones.size()); m_DominanceZones.push_back(newZone); pZone = &m_DominanceZones[m_DominanceZones.size() - 1]; } // Set zone for this cell pCell->SetDominanceZone(pZone->GetDominanceZoneID()); pZone->Extend(pPlot); }
CvPlot* CvPlayerAI::FindBestArtistTargetPlot(CvUnit* pGreatArtist, int& iResultScore) { CvAssertMsg(pGreatArtist, "pGreatArtist is null"); if(!pGreatArtist) { return NULL; } iResultScore = 0; CvPlotsVector& m_aiPlots = GetPlots(); CvPlot* pBestPlot = NULL; int iBestScore = 0; // loop through plots and wipe out ones that are invalid const uint nPlots = m_aiPlots.size(); for(uint ui = 0; ui < nPlots; ui++) { if(m_aiPlots[ui] == -1) { continue; } CvPlot* pPlot = GC.getMap().plotByIndex(m_aiPlots[ui]); if(pPlot->isWater()) { continue; } if(!pPlot->IsAdjacentOwnedByOtherTeam(getTeam())) { continue; } // don't build over luxury resources ResourceTypes eResource = pPlot->getResourceType(); if(eResource != NO_RESOURCE) { CvResourceInfo* pkResource = GC.getResourceInfo(eResource); if(pkResource != NULL) { if (pkResource->getResourceUsage() == RESOURCEUSAGE_LUXURY) { continue; } } } // if no improvement can be built on this plot, then don't consider it FeatureTypes eFeature = pPlot->getFeatureType(); if (eFeature != NO_FEATURE && GC.getFeatureInfo(eFeature)->isNoImprovement()) { continue; } // Improvement already here? ImprovementTypes eImprovement = (ImprovementTypes)pPlot->getImprovementType(); if (eImprovement != NO_IMPROVEMENT) { CvImprovementEntry* pkImprovementInfo = GC.getImprovementInfo(eImprovement); if(pkImprovementInfo) { if (pkImprovementInfo->GetCultureBombRadius() > 0) { continue; } } } int iScore = 0; for(int iI = 0; iI < NUM_DIRECTION_TYPES; ++iI) { CvPlot* pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)iI)); // if there's no plot, bail if(pAdjacentPlot == NULL) { continue; } // if the plot is ours or no one's, bail if(pAdjacentPlot->getTeam() == NO_TEAM || pAdjacentPlot->getTeam() == getTeam()) { continue; } // don't evaluate city plots since we don't get ownership of them with the bomb if(pAdjacentPlot->getPlotCity()) { continue; } const PlayerTypes eOtherPlayer = pAdjacentPlot->getOwner(); if(GET_PLAYER(eOtherPlayer).isMinorCiv()) { MinorCivApproachTypes eMinorApproach = GetDiplomacyAI()->GetMinorCivApproach(eOtherPlayer); // if we're friendly or protective, don't be a jerk. Bail out. if(eMinorApproach != MINOR_CIV_APPROACH_CONQUEST && eMinorApproach != MINOR_CIV_APPROACH_IGNORE) { iScore = 0; break; } } else { MajorCivApproachTypes eMajorApproach = GetDiplomacyAI()->GetMajorCivApproach(eOtherPlayer, true); DisputeLevelTypes eLandDisputeLevel = GetDiplomacyAI()->GetLandDisputeLevel(eOtherPlayer); bool bTicked = eMajorApproach == MAJOR_CIV_APPROACH_HOSTILE; bool bTickedAboutLand = eMajorApproach == MAJOR_CIV_APPROACH_NEUTRAL && (eLandDisputeLevel == DISPUTE_LEVEL_STRONG || eLandDisputeLevel == DISPUTE_LEVEL_FIERCE); // only bomb if we're hostile if(!bTicked && !bTickedAboutLand) { iScore = 0; break; } } eResource = pAdjacentPlot->getResourceType(); if(eResource != NO_RESOURCE) { iScore += GetBuilderTaskingAI()->GetResourceWeight(eResource, NO_IMPROVEMENT, pAdjacentPlot->getNumResource()) * 10; } else { for(int iYield = 0; iYield < NUM_YIELD_TYPES; iYield++) { iScore += pAdjacentPlot->getYield((YieldTypes)iYield); } } } if(iScore > iBestScore) { iBestScore = iScore; pBestPlot = pPlot; } } iResultScore = iBestScore; return pBestPlot; }
/// Retrieve the relative value of this plot (including plots that would be in city radius) int CvCitySiteEvaluator::PlotFoundValue(CvPlot* pPlot, CvPlayer* pPlayer, YieldTypes eYield, bool) { CvAssert(pPlot); if(!pPlot) return 0; // Make sure this player can even build a city here if(!CanFound(pPlot, pPlayer, false)) { return 0; } int rtnValue = 0; int iFoodValue = 0; int iHappinessValue = 0; int iProductionValue = 0; int iGoldValue = 0; int iScienceValue = 0; int iFaithValue = 0; int iResourceValue = 0; int iStrategicValue = 0; int iCelticForestCount = 0; int iIroquoisForestCount = 0; int iBrazilJungleCount = 0; int iNaturalWonderCount = 0; int iDesertCount = 0; int iWetlandsCount = 0; #if defined(MOD_BALANCE_CORE_SETTLER) int iWaterPlot = 0; int iBadPlot = 0; int iLoopPlots = 0; #endif int iTotalFoodValue = 0; int iTotalHappinessValue = 0; int iTotalProductionValue = 0; int iTotalGoldValue = 0; int iTotalScienceValue = 0; int iTotalFaithValue = 0; int iTotalResourceValue = 0; int iTotalStrategicValue = 0; int iClosestCityOfMine = 999; int iClosestEnemyCity = 999; int iCapitalArea = NULL; bool bIsInca = false; int iAdjacentMountains = 0; if ( pPlayer->getCapitalCity() ) iCapitalArea = pPlayer->getCapitalCity()->getArea(); // Custom code for Inca ideal terrace farm locations ImprovementTypes eIncaImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_TERRACE_FARM", true); if(eIncaImprovement != NO_IMPROVEMENT) { CvImprovementEntry* pkEntry = GC.getImprovementInfo(eIncaImprovement); if(pkEntry != NULL && pkEntry->IsSpecificCivRequired()) { CivilizationTypes eCiv = pkEntry->GetRequiredCivilization(); if(eCiv == pPlayer->getCivilizationType()) { bIsInca = true; } } } for (int iDX = -7; iDX <= 7; iDX++) { for (int iDY = -7; iDY <= 7; iDY++) { CvPlot* pLoopPlot = plotXY(pPlot->getX(), pPlot->getY(), iDX, iDY); if (pLoopPlot != NULL) { int iDistance = plotDistance(pPlot->getX(), pPlot->getY(), pLoopPlot->getX(), pLoopPlot->getY()); if (iDistance <= 7) { if ((pLoopPlot->getOwner() == NO_PLAYER) || (pLoopPlot->getOwner() == pPlayer->GetID())) { // See if there are other cities nearby if (iClosestCityOfMine > iDistance) { if (pLoopPlot->isCity()) { iClosestCityOfMine = iDistance; } } // Skip the city plot itself for now if (iDistance <= 5) { int iRingModifier = m_iRingModifier[iDistance]; iFoodValue = 0; iProductionValue = 0; iGoldValue = 0; iScienceValue = 0; iHappinessValue = 0; iResourceValue = 0; iStrategicValue = 0; #if defined(MOD_GLOBAL_CITY_WORKING) if (iDistance > 0 && iDistance <= pPlayer->getWorkPlotDistance()) #else if (iDistance > 0 && iDistance <= NUM_CITY_RINGS) #endif { if (eYield == NO_YIELD || eYield == YIELD_FOOD) { iFoodValue = iRingModifier * ComputeFoodValue(pLoopPlot, pPlayer) * /*15*/ GC.getSETTLER_FOOD_MULTIPLIER(); } if (eYield == NO_YIELD || eYield == YIELD_PRODUCTION) { iProductionValue = iRingModifier * ComputeProductionValue(pLoopPlot, pPlayer) * /*3*/ GC.getSETTLER_PRODUCTION_MULTIPLIER(); } if (eYield == NO_YIELD || eYield == YIELD_GOLD) { iGoldValue = iRingModifier * ComputeGoldValue(pLoopPlot, pPlayer) * /*2*/ GC.getSETTLER_GOLD_MULTIPLIER(); } if (eYield == NO_YIELD || eYield == YIELD_SCIENCE) { iScienceValue = iRingModifier * ComputeScienceValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_SCIENCE_MULTIPLIER(); } if (eYield == NO_YIELD || eYield == YIELD_FAITH) { iFaithValue = iRingModifier * ComputeFaithValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_FAITH_MULTIPLIER(); } } // whether or not we are working these we get the benefit as long as culture can grow to take them if (iDistance <= 5 && pLoopPlot->getOwner() == NO_PLAYER) // there is no benefit if we already own these tiles { iHappinessValue = iRingModifier * ComputeHappinessValue(pLoopPlot, pPlayer) * /*6*/ GC.getSETTLER_HAPPINESS_MULTIPLIER(); iResourceValue = iRingModifier * ComputeTradeableResourceValue(pLoopPlot, pPlayer) * /*1*/ GC.getSETTLER_RESOURCE_MULTIPLIER(); if (iDistance) iStrategicValue = ComputeStrategicValue(pLoopPlot, pPlayer, iDistance) * /*1*/ GC.getSETTLER_STRATEGIC_MULTIPLIER(); // the ring is included in the computation } iTotalFoodValue += iFoodValue; iTotalHappinessValue += iHappinessValue; iTotalProductionValue += iProductionValue; iTotalGoldValue += iGoldValue; iTotalScienceValue += iScienceValue; iTotalFaithValue += iFaithValue; iTotalResourceValue += iResourceValue; iTotalStrategicValue += iStrategicValue; int iPlotValue = iFoodValue + iHappinessValue + iProductionValue + iGoldValue + iScienceValue + iFaithValue + iResourceValue; if (iPlotValue == 0) { // this tile is so bad it gets negatives iPlotValue -= iRingModifier * GC.getSETTLER_FOOD_MULTIPLIER() * 2; } iPlotValue += iStrategicValue; // if this tile is a NW boost the value just so that we force the AI to claim them (if we can work it) #if defined(MOD_GLOBAL_CITY_WORKING) if (pLoopPlot->IsNaturalWonder() && iDistance > 0 && iDistance <= pPlayer->getWorkPlotDistance()) #else if (pLoopPlot->IsNaturalWonder() && iDistance > 0 && iDistance <= NUM_CITY_RINGS) #endif { //iPlotValue += iPlotValue * 2 + 10; iPlotValue += iPlotValue * 2 + 500; } // lower value a lot if we already own this tile if (iPlotValue > 0 && pLoopPlot->getOwner() == pPlayer->GetID()) { #if defined(MOD_BALANCE_CORE_SETTLER) if (MOD_BALANCE_CORE_SETTLER) { iPlotValue *= 2; iPlotValue /= 3; } #else iPlotValue /= 4; #endif } // add this plot into the total rtnValue += iPlotValue; FeatureTypes ePlotFeature = pLoopPlot->getFeatureType(); ImprovementTypes ePlotImprovement = pLoopPlot->getImprovementType(); ResourceTypes ePlotResource = pLoopPlot->getResourceType(); if (ePlotFeature == FEATURE_FOREST) { if (iDistance <= 5) { ++iIroquoisForestCount; if (iDistance == 1) { if (ePlotImprovement == NO_IMPROVEMENT) { ++iCelticForestCount; } } } } else if (ePlotFeature == FEATURE_JUNGLE) { #if defined(MOD_GLOBAL_CITY_WORKING) if (iDistance <= pPlayer->getWorkPlotDistance()) #else if (iDistance <= NUM_CITY_RINGS) #endif { ++iBrazilJungleCount; } } else if (ePlotFeature == FEATURE_MARSH || ePlotFeature == FEATURE_FLOOD_PLAINS) { #if defined(MOD_GLOBAL_CITY_WORKING) if (iDistance <= pPlayer->getWorkPlotDistance()) #else if (iDistance <= NUM_CITY_RINGS) #endif { ++iWetlandsCount; } } if (pLoopPlot->IsNaturalWonder()) { if (iDistance <= 1) { ++iNaturalWonderCount; } } if (pLoopPlot->getTerrainType() == TERRAIN_DESERT) { #if defined(MOD_GLOBAL_CITY_WORKING) if (iDistance <= pPlayer->getWorkPlotDistance()) #else if (iDistance <= NUM_CITY_RINGS) #endif { if (ePlotResource == NO_RESOURCE) { ++iDesertCount; } } } if (bIsInca) { if (pLoopPlot->isHills()) { #if defined(MOD_GLOBAL_CITY_WORKING) if (iDistance <= pPlayer->getWorkPlotDistance()) #else if (iDistance <= NUM_CITY_RINGS) #endif { iAdjacentMountains = pLoopPlot->GetNumAdjacentMountains(); if (iAdjacentMountains > 0 && iAdjacentMountains < 6) { //give the bonus if it's hills, with additional if bordered by mountains rtnValue += m_iIncaMultiplier + (iAdjacentMountains * m_iIncaMultiplier); } } } } #if defined(MOD_BALANCE_CORE_SETTLER) if (MOD_BALANCE_CORE_SETTLER) { if(pLoopPlot->isWater() && pLoopPlot->HasResource(NO_RESOURCE)) { iWaterPlot++; } if(pLoopPlot == NULL || pLoopPlot->isImpassable() || pLoopPlot->getTerrainType() == TERRAIN_SNOW || pLoopPlot->getFeatureType() == FEATURE_ICE) { iBadPlot++; } } #endif } } else // this tile is owned by someone else { // See if there are other cities nearby (only count major civs) if (iClosestEnemyCity > iDistance) { if (pLoopPlot->isCity() && (pLoopPlot->getOwner() < MAX_MAJOR_CIVS)) { iClosestEnemyCity = iDistance; } } } } } #if defined(MOD_BALANCE_CORE_SETTLER) if (MOD_BALANCE_CORE_SETTLER) { iLoopPlots++; } #endif } } if (pPlayer->GetPlayerTraits()->IsFaithFromUnimprovedForest()) { if (iCelticForestCount >= 3) { rtnValue += 2 * 1000 * m_iFlavorMultiplier[YIELD_FAITH]; } else if (iCelticForestCount >= 1) { rtnValue += 1 * 1000 * m_iFlavorMultiplier[YIELD_FAITH]; } } else if (pPlayer->GetPlayerTraits()->IsMoveFriendlyWoodsAsRoad()) { rtnValue += iIroquoisForestCount * 10; } else if (pPlayer->GetPlayerTraits()->GetNaturalWonderYieldModifier() > 0) //ie: Spain { rtnValue += iNaturalWonderCount * m_iSpainMultiplier; } // Custom code for Brazil ImprovementTypes eBrazilImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_BRAZILWOOD_CAMP", true); if(eBrazilImprovement != NO_IMPROVEMENT) { CvImprovementEntry* pkEntry = GC.getImprovementInfo(eBrazilImprovement); if(pkEntry != NULL && pkEntry->IsSpecificCivRequired()) { CivilizationTypes eCiv = pkEntry->GetRequiredCivilization(); if(eCiv == pPlayer->getCivilizationType()) { rtnValue += iBrazilJungleCount * m_iBrazilMultiplier; } } } // Custom code for Morocco ImprovementTypes eMoroccoImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_KASBAH", true); if(eMoroccoImprovement != NO_IMPROVEMENT) { CvImprovementEntry* pkEntry = GC.getImprovementInfo(eMoroccoImprovement); if(pkEntry != NULL && pkEntry->IsSpecificCivRequired()) { CivilizationTypes eCiv = pkEntry->GetRequiredCivilization(); if(eCiv == pPlayer->getCivilizationType()) { rtnValue += iDesertCount * m_iMorrocoMultiplier; } } } //Custom code for Netherlands ImprovementTypes ePolderImprovement = (ImprovementTypes)GC.getInfoTypeForString("IMPROVEMENT_POLDER", true); if(ePolderImprovement != NO_IMPROVEMENT) { CvImprovementEntry* pkEntry = GC.getImprovementInfo(ePolderImprovement); if(pkEntry != NULL && pkEntry->IsSpecificCivRequired()) { CivilizationTypes eCiv = pkEntry->GetRequiredCivilization(); if(eCiv == pPlayer->getCivilizationType()) { rtnValue += iWetlandsCount * m_iNetherlandsMultiplier; } } } if (rtnValue < 0) rtnValue = 0; // Finally, look at the city plot itself and use it as an overall multiplier if (pPlot->getResourceType(pPlayer->getTeam()) != NO_RESOURCE) { rtnValue += (int)rtnValue * /*-50*/ GC.getBUILD_ON_RESOURCE_PERCENT() / 100; } if (pPlot->isRiver()) { rtnValue += (int)rtnValue * /*15*/ GC.getBUILD_ON_RIVER_PERCENT() / 100; } if (pPlot->isCoastalLand(GC.getMIN_WATER_SIZE_FOR_OCEAN())) { // okay, coast used to have lots of gold so players settled there "naturally", it doesn't any more, so I am going to give it a nudge in that direction // slewis - removed Brian(?)'s rtnValue adjustment and raised the BUILD_ON_COAST_PERCENT to 40 from 25 //rtnValue += rtnValue > 0 ? 10 : 0; rtnValue += (int)rtnValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT() / 100; int iNavalFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iNavalIndex); if (iNavalFlavor > 7) { rtnValue += (int)rtnValue * /*40*/ GC.getSETTLER_BUILD_ON_COAST_PERCENT() / 100; } if (pPlayer->getCivilizationInfo().isCoastalCiv()) // we really like the coast (England, Norway, Polynesia, Carthage, etc.) { rtnValue += rtnValue > 0 ? 25 : 0; rtnValue *= 2; } } #if defined(MOD_BALANCE_CORE_SETTLER) if (MOD_BALANCE_CORE_SETTLER) { //Is this a water chokepoint? (More than four would make this a peninsula, which is not what we are looking for.) if(pPlot->IsChokePoint(true, false, 0)) { rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 100; } //Looking for mountains for chokepoints. //If the adjacent plot is not touching another mountain, and there is more than one mountain around pPlot, we've found a potential chokepoint. else if(pPlot->IsChokePoint(false, true, 1)) { //Awesome, we found a mountain chokepoint within 1. Emphasize! rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 75; } else if(pPlot->IsChokePoint(false, true, 2)) { //Awesome, we found a mountain chokepoint within 2. Emphasize! rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 100; } else if(pPlot->IsChokePoint(false, true, 3)) { //Awesome, we found a mountain chokepoint within 3. Emphasize! rtnValue += (int)rtnValue * /*100*/ GC.getBALANCE_CHOKEPOINT_STRATEGIC_VALUE() / 125; } //Too many bad plots? if(iBadPlot > (iLoopPlots / 4)) { rtnValue /= 5; } //Too much empty water? if(iWaterPlot > (iLoopPlots / 2)) { rtnValue *= 2; rtnValue /= 3; } } //Let's see what we can do. (Strategic site locator pulled from below - less loop cycles used this way, as all we care about is the city plot itself, not every plot in the city's loop. if(pPlayer != NULL) { for(int iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++) { PlayerTypes eOtherPlayer = (PlayerTypes) iMajorLoop; PlayerProximityTypes eProximity = GET_PLAYER(eOtherPlayer).GetProximityToPlayer(pPlayer->GetID()); if(eOtherPlayer != pPlayer->GetID() && eOtherPlayer != NO_PLAYER && GET_PLAYER(eOtherPlayer).isAlive() && !GET_PLAYER(eOtherPlayer).isMinorCiv() && !GET_PLAYER(eOtherPlayer).isBarbarian()) { if(eProximity >= PLAYER_PROXIMITY_CLOSE) { CvCity* pLoopTheirCity; int iClosestDistance = 6; int iDistance = 0; int iLoop; for(pLoopTheirCity = GET_PLAYER(eOtherPlayer).firstCity(&iLoop); pLoopTheirCity != NULL; pLoopTheirCity = GET_PLAYER(eOtherPlayer).nextCity(&iLoop)) { if(pLoopTheirCity != NULL) { if(pPlot->getArea() == pLoopTheirCity->getArea()) { iDistance = plotDistance(pPlot->getX(), pPlot->getY(), pLoopTheirCity->getX(), pLoopTheirCity->getY()); if(iDistance <= iClosestDistance) { //There's at least 6 hexes between these plots, which means we can theoretically settle here. int iNumPlots = 0; int iNumBadPlots = 0; for(int iDX = -iClosestDistance; iDX <= iClosestDistance; iDX++) { for(int iDY = -iClosestDistance; iDY <= iClosestDistance; iDY++) { CvPlot* pLoopPlot = plotXYWithRangeCheck(pPlot->getX(), pPlot->getY(), iDX, iDY, iClosestDistance); if(pLoopPlot) { //Let's look for good, empty land. if(pLoopPlot->isImpassable() || pLoopPlot->isWater() || pLoopPlot->getOwner() != NO_PLAYER) { iNumBadPlots++; } iNumPlots++; } } } if(iNumBadPlots > 0) { iNumBadPlots = (iNumBadPlots * 130) / 100; } //Good space must be greater than bad plots by at least 30% if(iNumPlots > iNumBadPlots) { //If there is significant empty land, and it is within the theoretical hex separation of the nearest two cities of two different players, there's a good chance it is border land. GET IT! rtnValue += (int)rtnValue * /*50*/ GC.getBALANCE_EMPIRE_BORDERLAND_STRATEGIC_VALUE() / 100; break; } } } } } } } } } #endif // Nearby Cities? // Human if (pPlayer != NULL && pPlayer->isHuman()) { if (iClosestCityOfMine == 3) { rtnValue /= 2; } } // AI else { int iGrowthFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iGrowthIndex); int iExpansionFlavor = pPlayer->GetGrandStrategyAI()->GetPersonalityAndGrandStrategy((FlavorTypes)m_iExpansionIndex); int iSweetSpot = 5; iSweetSpot += (iGrowthFlavor > 7) ? 1 : 0; iSweetSpot += (iExpansionFlavor > 7) ? -1 : 0; iSweetSpot += (iGrowthFlavor < 4) ? -1 : 0; iSweetSpot += (iExpansionFlavor < 4) ? 1 : 0; iSweetSpot = max(4,iSweetSpot); iSweetSpot = min(6,iSweetSpot); if (iClosestCityOfMine == iSweetSpot) { // 1.5 was not enough 2.0 was too much, so lets split the difference rtnValue *= 175; rtnValue /= 100; } else if (iClosestCityOfMine < iSweetSpot) { rtnValue /= 2; } else if (iClosestCityOfMine > 7) { rtnValue *= 2; rtnValue /= 3; } // use boldness to decide if we want to push close to enemies int iBoldness = pPlayer->GetDiplomacyAI()->GetBoldness(); if (iBoldness < 4) { if (iClosestEnemyCity <= 4) { rtnValue /= 4; } else if (iClosestEnemyCity == 5) { rtnValue /= 2; } } else if (iBoldness > 7) { if (iClosestEnemyCity <= 5 && iClosestCityOfMine < 8) { rtnValue *= 3; rtnValue /= 2; } } else { if (iClosestEnemyCity < 5) { rtnValue *= 2; rtnValue /= 3; } } // if we are offshore, pull cities in tighter if (iCapitalArea != pPlot->getArea()) { if (iClosestCityOfMine < 7) { rtnValue *= 3; rtnValue /= 2; } } #if defined(MOD_BALANCE_CORE_SETTLER) if (MOD_BALANCE_CORE_SETTLER) { //Let's judge just how well we can defend this city if we push out. If our neighbors are stronger than us, let's turtle a bit. for(int iMajorLoop = 0; iMajorLoop < MAX_MAJOR_CIVS; iMajorLoop++) { PlayerTypes eOtherPlayer = (PlayerTypes) iMajorLoop; if(eOtherPlayer != NO_PLAYER && GET_PLAYER(eOtherPlayer).isAlive() && !GET_PLAYER(eOtherPlayer).isMinorCiv() && !GET_PLAYER(eOtherPlayer).isBarbarian()) { PlayerProximityTypes eProximity = GET_PLAYER(eOtherPlayer).GetProximityToPlayer(pPlayer->GetID()); if(eProximity == PLAYER_PROXIMITY_NEIGHBORS && (pPlayer->GetMilitaryMight() < GET_PLAYER(eOtherPlayer).GetMilitaryMight())) { //Is the plot we're looking at in the same area as our strong neighbor? if (iClosestEnemyCity <= 6) { rtnValue /= 2; } } } } } #endif } rtnValue = (rtnValue > 0) ? rtnValue : 0; return rtnValue; }
void CvDistanceMap::Dump(const char* filename) { ofstream out(filename); if (out) { out << "#x,y,hx,hz,water,distance,id,owner\n"; for (int i=0; i<GC.getMap().numPlots(); i++) { CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(i); int xHex = xToHexspaceX(pPlot->getX(),pPlot->getY()); int zHex = -xHex-pPlot->getY(); out << pPlot->getX() << "," << pPlot->getY() << "," << xHex << "," << zHex << "," << (pPlot->isWater() ? 1 : 0) << "," << GetClosestFeatureDistance(*pPlot) << "," << GetClosestFeatureID(*pPlot) << "," << GetClosestFeatureOwner(*pPlot) << "\n"; } } out.close(); }