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; }
/// Recalculate when each unit will arrive on target void CvArmyAI::UpdateCheckpointTurns() { for(unsigned int iI = 0; iI < m_FormationEntries.size(); iI++) { // No reestimate for units being built if(m_FormationEntries[iI].GetUnitID() != ARMY_NO_UNIT) { CvUnit* pUnit = GET_PLAYER(m_eOwner).getUnit(m_FormationEntries[iI].GetUnitID()); CvPlot* pMusterPlot = GC.getMap().plot(GetX(), GetY()); if(pUnit && pMusterPlot) { int iTurnsToReachCheckpoint = TurnsToReachTarget(pUnit, pMusterPlot, true /*bReusePaths*/, true, true); if(iTurnsToReachCheckpoint < MAX_INT) { SetEstimatedTurn(iI, iTurnsToReachCheckpoint); } } } } }
/// Add a unit to our army (and we know which slot) void CvArmyAI::AddUnit(int iUnitID, int iSlotNum) { CvAssertMsg(iUnitID != ARMY_NO_UNIT,"Expect unit to be non-NULL"); CvPlayer& thisPlayer = GET_PLAYER(m_eOwner); UnitHandle pThisUnit = thisPlayer.getUnit(iUnitID); // remove this unit from an army if it is already in one thisPlayer.removeFromArmy(pThisUnit->getArmyID(), GetID()); m_FormationEntries[iSlotNum].SetUnitID(iUnitID); pThisUnit->setArmyID(GetID()); // Finally, compute when we think this unit will arrive at the next checkpoint CvPlot* pMusterPlot = GC.getMap().plot(GetX(), GetY()); if(pMusterPlot) { int iTurnsToReachCheckpoint = TurnsToReachTarget(pThisUnit, pMusterPlot, true /*bReusePaths*/, true, true); if(iTurnsToReachCheckpoint < MAX_INT) { SetEstimatedTurn(iSlotNum, iTurnsToReachCheckpoint); } } }
CvPlot* CvPlayerAI::FindBestMusicianTargetPlot(CvUnit* pGreatMusician, bool bOnlySafePaths) { CvAssertMsg(pGreatMusician, "pGreatMusician is null"); if(!pGreatMusician) { return NULL; } int iBestTurnsToReach = MAX_INT; CvPlot* pBestTargetPlot = NULL; CvCity* pBestTargetCity = NULL; int iPathTurns; UnitHandle pMusician = UnitHandle(pGreatMusician); // Find target civ PlayerTypes eTargetPlayer = GetCulture()->GetCivLowestInfluence(true /*bCheckOpenBorders*/); if (eTargetPlayer == NO_PLAYER) { return NULL; } CvPlayer &kTargetPlayer = GET_PLAYER(eTargetPlayer); // Loop through each of that player's cities int iLoop; CvCity *pLoopCity; for(pLoopCity = kTargetPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kTargetPlayer.nextCity(&iLoop)) { // Search all the plots adjacent to this city for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++) { CvPlot* pAdjacentPlot = plotDirection(pLoopCity->getX(), pLoopCity->getY(), ((DirectionTypes)jJ)); if(pAdjacentPlot != NULL) { // Make sure this is still owned by target and is revealed to us bool bRightOwner = (pAdjacentPlot->getOwner() == eTargetPlayer); bool bIsRevealed = pAdjacentPlot->isRevealed(getTeam()); if(bRightOwner && bIsRevealed) { iPathTurns = TurnsToReachTarget(pMusician, pAdjacentPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/); if(iPathTurns < iBestTurnsToReach) { iBestTurnsToReach = iPathTurns; pBestTargetCity = pLoopCity; } } } } } // Found a city now look at ALL the plots owned by that player near that city if (pBestTargetCity) { iBestTurnsToReach = MAX_INT; CvPlot *pLoopPlot; for(int iJ = 0; iJ < NUM_CITY_PLOTS; iJ++) { pLoopPlot = plotCity(pBestTargetCity->getX(), pBestTargetCity->getY(), iJ); if(pLoopPlot != NULL) { // Make sure this is still owned by target and is revealed to us bool bRightOwner = (pLoopPlot->getOwner() == eTargetPlayer); bool bIsRevealed = pLoopPlot->isRevealed(getTeam()); if(bRightOwner && bIsRevealed) { iPathTurns = TurnsToReachTarget(pMusician, pLoopPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/); if(iPathTurns < iBestTurnsToReach) { iBestTurnsToReach = iPathTurns; pBestTargetPlot = pLoopPlot; } } } } } return pBestTargetPlot; }
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()); //bool bIsVenice = GetPlayerTraits()->IsNoAnnexing(); //bool bWantsCash = GreatMerchantWantsCash(); // Loop through each city state for(int iI = 0; iI < MAX_PLAYERS; iI++) { CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)iI); if (!kPlayer.isMinorCiv()) { continue; } // if I'm Venice, I don't want to send a Merchant of Venice to a buy a city that I have trade routes // with because it's probably more valuable as a trade partner than as an owned entity //if (!bWantsCash) //{ // if (bIsVenice) // { // if (GetTrade()->IsConnectedToPlayer(kPlayer.GetID())) // { // continue; // } // } //} CvPlot* pCSPlot = kPlayer.getStartingPlot(); if (!pCSPlot) { continue; } if (!pCSPlot->isRevealed(getTeam())) { continue; } // Is this a minor we are friendly with? bool bMinorCivApproachIsCorrect = (GetDiplomacyAI()->GetMinorCivApproach(kPlayer.GetID()) != MINOR_CIV_APPROACH_CONQUEST); bool bNotAtWar = !kTeam.isAtWar(kPlayer.getTeam()); bool bNotPlanningAWar = GetDiplomacyAI()->GetWarGoal(kPlayer.GetID()) == NO_WAR_GOAL_TYPE; if(bMinorCivApproachIsCorrect && bNotAtWar && bNotPlanningAWar) { // 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()) bool bRightOwner = (pAdjacentPlot->getOwner() == (PlayerTypes)iI); bool bIsRevealed = pAdjacentPlot->isRevealed(getTeam()); if(bRightOwner && bIsRevealed) { iPathTurns = TurnsToReachTarget(pMerchant, pAdjacentPlot, true /*bReusePaths*/, !bOnlySafePaths/*bIgnoreUnits*/); if(iPathTurns < iBestTurnsToReach) { iBestTurnsToReach = iPathTurns; pBestTargetPlot = pAdjacentPlot; } } } } } } return pBestTargetPlot; }
// Indicate the plots we might want to move to that the enemy can attack void CvTacticalAnalysisMap::MarkCellsNearEnemy() { int iDistance; // Look at every cell on the map for(int iI = 0; iI < GC.getMap().numPlots(); iI++) { bool bMarkedIt = false; // Set true once we've found one that enemy can move past (worst case) CvPlot* pPlot = GC.getMap().plotByIndexUnchecked(iI); if(m_pPlots[iI].IsRevealed() && !m_pPlots[iI].IsImpassableTerrain() && !m_pPlots[iI].IsImpassableTerritory()) { // Friendly cities always safe if(!m_pPlots[iI].IsFriendlyCity()) { if(!pPlot->isVisibleToEnemyTeam(m_pPlayer->getTeam())) { m_pPlots[iI].SetNotVisibleToEnemy(true); } else { for(unsigned int iUnitIndex = 0; iUnitIndex < m_EnemyUnits.size() && !bMarkedIt; iUnitIndex++) { CvUnit* pUnit = m_EnemyUnits[iUnitIndex]; if(pUnit->getArea() == pPlot->getArea()) { // Distance check before hitting pathfinder iDistance = plotDistance(pUnit->getX(), pUnit->getY(), pPlot->getX(), pPlot->getY()); if(iDistance == 0) { m_pPlots[iI].SetSubjectToAttack(true); m_pPlots[iI].SetEnemyCanMovePast(true); bMarkedIt = true; } // TEMPORARY OPTIMIZATION: Assumes can't use roads or RR else if(iDistance <= pUnit->baseMoves()) { int iTurnsToReach; iTurnsToReach = TurnsToReachTarget(pUnit, pPlot, true /*bReusePaths*/, true /*bIgnoreUnits*/); // Its ok to reuse paths because when ignoring units, we don't use the tactical analysis map (which we are building) if(iTurnsToReach <= 1) { m_pPlots[iI].SetSubjectToAttack(true); } if(iTurnsToReach == 0) { m_pPlots[iI].SetEnemyCanMovePast(true); bMarkedIt = true; } } } } // Check adjacent plots for enemy citadels if(!m_pPlots[iI].IsSubjectToAttack()) { CvPlot* pAdjacentPlot; for(int jJ = 0; jJ < NUM_DIRECTION_TYPES; jJ++) { pAdjacentPlot = plotDirection(pPlot->getX(), pPlot->getY(), ((DirectionTypes)jJ)); if(pAdjacentPlot != NULL && pAdjacentPlot->getOwner() != NO_PLAYER) { if(atWar(m_pPlayer->getTeam(), GET_PLAYER(pAdjacentPlot->getOwner()).getTeam())) { ImprovementTypes eImprovement = pAdjacentPlot->getImprovementType(); if(eImprovement != NO_IMPROVEMENT && GC.getImprovementInfo(eImprovement)->GetNearbyEnemyDamage() > 0) { m_pPlots[iI].SetSubjectToAttack(true); break; } } } } } } } } } }