Civ Illustrated #1 (Know Your Enemy)

Flavors - What an AI tends to tech more often

I've noticed that Civ Illustrated #1 has some broken links due to important hosted files dying over the years as college was graduated, accounts were closed, etc.

Flavors was one of the casualties, so I'm fixing it right now. :D
https://forums.civfanatics.com/threads/civ-illustrated-1-know-your-enemy.478563/#post-11931677
10) Flavors describe what kind of techs a civilization pursues. The flavor strength was converted from numbers to words as follows:

Flavor
2->Low
5->Medium
10->High

There are many factors that determine what technology a civ will pursue such as a random variable, a free tech or free great person (massive influence!), unlocks a religion(bigger factor if favorite), unlocks a unit, unlocks a wonder, unlocks a civic(bigger factor if favorite), the strategy the AI is pursuing, planning a war etc. It is thought that the flavor of the AI affects the tech choice perhaps 33% of the time.

All the techs in the game with the various flavors can be found here.
All the calculated values for the various AI based off their flavors and the flavors of the techs can be found here.

Just looking at those results, it becomes apparent that Joao, Lincoln, Peter, and Tokugawa like Education more than the rest of the AI and are more likely to tech it.

Running through a calculation: Hatshepsut has religion flavor of 2(Low) and culture flavor of 5(Medium). Aesthetics has religion flavor of 2, science flavor of 6, and culture flavor of 8. So Hatshepsut calculates Aesthetics to have a value of 2*2+5*8=44. Mathematics has gold flavor of 2, production flavor of 1, military flavor of 1, and science flavor of 10. So Hatshepsut calculated Mathematics to have a value of 0. She will tend to tech Aesthetics before Mathematics.

Since flavors only influence what techs are researched to a limited degree, the usefulness on this info isn't as great as it could be. However, there is no denying that on average Isabella techs religions and Genghis Khan goes after Military Tradition, Rifling, and Artillery when they get the chance.
There is no way I'm calculating and writing out all results 52 AI have for all 92 techs in a forum post! (4784 numbers)
All that stuff is going in a spreadsheet using OpenOffice that is free program to download and use.

I labored over the .XML files to get all the flavor values for the techs, copied some stuff from DanF's spreadsheet, and added in some Vlookup functions.
All that is required is selecting the AI and gazing at their flavor values for tech choices.
Spoiler :
Instructions were left on how to sort the results.
Spoiler :




Click on Sheet 2 in the bottom left corner of the spreadsheet to see all the leader and tech flavor values.
Tech costs in :science: are the base values for a player without any modifiers on Noble difficulty, Duel-sized map, Normal Speed.


I'll compress the spreadsheet into a .zip file and attach it at the bottom of this post.
If you can't unzip files for some reason, I think 7zip is a decent program.

Make sure to extract the file completely onto the desktop.
Otherwise it will say (Read-Only) and it is impossible to use the sort function. :sad:
 

Attachments

  • Flavor Spreadsheet Civ 4 BTS 2.0.zip
    23.7 KB · Views: 18
Right, base attitude an AI has is not just towards the human player, but the other AI as well.


I'll fix Civ Illustrated this month.

The priorities must be border tension diplomatic consequences with an explanation of land target status, turns before an AI will talk peace with the needed war success to achieve maximum reductions (both for when the AI starts the war which is double turns and also when human starts the war), and a final concrete measurement of unit aggression for each civ.
 
There are 3 kinds of war that the AI wages in Civ 4 as shown here. They are Total War(Max War), Limited War, and Dogpile War. Each AI has a separate rating and desire for each of these types of war. These ratings are located in the WarVals section of the LeaderHead Info spreadsheet. Rather than have 3 separate war ratings for each civ, it was decided by members of Civ Illustrated that the average user would not be able to tell the difference between what type of war an AI was waging. So the most important type of war was selected, the kind the AI wages when it wants to conquer you, Total War!

The amazing DanF5771 provides a very in-depth look at the exact process the AI goes through when deciding to war here. (Hint: Don't settle your cities close to each other :))
From this guide, we see that the base chance per turn that an AI will decide to go to total war with somebody is (100/iMaxWarRand). Gandhi has a 0.25% base chance each turn and Ragnar, Montezuma, Alexander, etc. has a 2% chance each turn.
If DanF's war decision tree is a bit hard to read, try Smurkz's explanation.
https://forums.civfanatics.com/threads/sgotm-07-smurkz.271903/page-20#post-6806299

This part of the guide is also creaking with age and might be misleading people a bit.



Team Smurkz's explanation of how an AI decides to go to war as explained by Niklas if for Vanilla Civ.

Also, DanF5771's very detailed explanation of how an AI decides to go to war was posted on August 9, 2008.

Civ 4 Beyond the Sword had patch 3.19 in on June 10th, 2009 about a year later.

Fixed bug with AI not knowing how close its cities are to other players

So DanF5771's AI war decision post might need updating if "Don't settle your cities close to each other" got fixed in a patch. :hmm:



The simplest part to focus on might be updating how the AI picks a war target when it chooses 2 or more possible candidates after the power check is passed and the diplomatic situation does not produce a NoWar roll in the victim's favor.
Which target is the juiciest for the AI to declare war upon?

Here is the code where the game calculates that I think from CivTeamAI.cpp:

Spoiler CivTeamAI.cpp :

Code:
// teamAI.cpp

#include "CvGameCoreDLL.h"
#include "CvTeamAI.h"
#include "CvPlayerAI.h"
#include "CvRandom.h"
#include "CvGlobals.h"
#include "CvGameCoreUtils.h"
#include "CvMap.h"
#include "CvPlot.h"
#include "CvDLLInterfaceIFaceBase.h"
#include "CvGameAI.h"
#include "CvInfos.h"
#include "FProfiler.h"
#include "CyArgsList.h"
#include "CvDLLPythonIFaceBase.h"

// statics

CvTeamAI* CvTeamAI::m_aTeams = NULL;

void CvTeamAI::initStatics()
{
    m_aTeams = new CvTeamAI[MAX_TEAMS];
    for (int iI = 0; iI < MAX_PLAYERS; iI++)
    {
        m_aTeams[iI].m_eID = ((TeamTypes)iI);
    }
}

void CvTeamAI::freeStatics()
{
    SAFE_DELETE_ARRAY(m_aTeams);
}

// inlined for performance reasons
DllExport CvTeamAI& CvTeamAI::getTeamNonInl(TeamTypes eTeam)
{
    return getTeam(eTeam);
}


// Public Functions...

CvTeamAI::CvTeamAI()
{
    m_aiWarPlanStateCounter = new int[MAX_TEAMS];
    m_aiAtWarCounter = new int[MAX_TEAMS];
    m_aiAtPeaceCounter = new int[MAX_TEAMS];
    m_aiHasMetCounter = new int[MAX_TEAMS];
    m_aiOpenBordersCounter = new int[MAX_TEAMS];
    m_aiDefensivePactCounter = new int[MAX_TEAMS];
    m_aiShareWarCounter = new int[MAX_TEAMS];
    m_aiWarSuccess = new int[MAX_TEAMS];
    m_aiEnemyPeacetimeTradeValue = new int[MAX_TEAMS];
    m_aiEnemyPeacetimeGrantValue = new int[MAX_TEAMS];
    m_aeWarPlan = new WarPlanTypes[MAX_TEAMS];


    AI_reset(true);
}


CvTeamAI::~CvTeamAI()
{
    AI_uninit();

    SAFE_DELETE_ARRAY(m_aiWarPlanStateCounter);
    SAFE_DELETE_ARRAY(m_aiAtWarCounter);
    SAFE_DELETE_ARRAY(m_aiAtPeaceCounter);
    SAFE_DELETE_ARRAY(m_aiHasMetCounter);
    SAFE_DELETE_ARRAY(m_aiOpenBordersCounter);
    SAFE_DELETE_ARRAY(m_aiDefensivePactCounter);
    SAFE_DELETE_ARRAY(m_aiShareWarCounter);
    SAFE_DELETE_ARRAY(m_aiWarSuccess);
    SAFE_DELETE_ARRAY(m_aiEnemyPeacetimeTradeValue);
    SAFE_DELETE_ARRAY(m_aiEnemyPeacetimeGrantValue);
    SAFE_DELETE_ARRAY(m_aeWarPlan);
}


void CvTeamAI::AI_init()
{
    AI_reset(false);

    //--------------------------------
    // Init other game data
}


void CvTeamAI::AI_uninit()
{
}


void CvTeamAI::AI_reset(bool bConstructor)
{
    AI_uninit();

    m_eWorstEnemy = NO_TEAM;

    for (int iI = 0; iI < MAX_TEAMS; iI++)
    {
        m_aiWarPlanStateCounter[iI] = 0;
        m_aiAtWarCounter[iI] = 0;
        m_aiAtPeaceCounter[iI] = 0;
        m_aiHasMetCounter[iI] = 0;
        m_aiOpenBordersCounter[iI] = 0;
        m_aiDefensivePactCounter[iI] = 0;
        m_aiShareWarCounter[iI] = 0;
        m_aiWarSuccess[iI] = 0;
        m_aiEnemyPeacetimeTradeValue[iI] = 0;
        m_aiEnemyPeacetimeGrantValue[iI] = 0;
        m_aeWarPlan[iI] = NO_WARPLAN;

        if (!bConstructor && getID() != NO_TEAM)
        {
            TeamTypes eLoopTeam = (TeamTypes) iI;
            CvTeamAI& kLoopTeam = GET_TEAM(eLoopTeam);
            kLoopTeam.m_aiWarPlanStateCounter[getID()] = 0;
            kLoopTeam.m_aiAtWarCounter[getID()] = 0;
            kLoopTeam.m_aiAtPeaceCounter[getID()] = 0;
            kLoopTeam.m_aiHasMetCounter[getID()] = 0;
            kLoopTeam.m_aiOpenBordersCounter[getID()] = 0;
            kLoopTeam.m_aiDefensivePactCounter[getID()] = 0;
            kLoopTeam.m_aiShareWarCounter[getID()] = 0;
            kLoopTeam.m_aiWarSuccess[getID()] = 0;
            kLoopTeam.m_aiEnemyPeacetimeTradeValue[getID()] = 0;
            kLoopTeam.m_aiEnemyPeacetimeGrantValue[getID()] = 0;
            kLoopTeam.m_aeWarPlan[getID()] = NO_WARPLAN;
        }
    }
}


void CvTeamAI::AI_doTurnPre()
{
    AI_doCounter();

    if (isHuman())
    {
        return;
    }

    if (isBarbarian())
    {
        return;
    }

    if (isMinorCiv())
    {
        return;
    }
}


void CvTeamAI::AI_doTurnPost()
{
    AI_updateWorstEnemy();

    AI_updateAreaStragies(false);

    if (isHuman())
    {
        return;
    }

    if (isBarbarian())
    {
        return;
    }

    if (isMinorCiv())
    {
        return;
    }

    AI_doWar();
}


void CvTeamAI::AI_makeAssignWorkDirty()
{
    int iI;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                GET_PLAYER((PlayerTypes)iI).AI_makeAssignWorkDirty();
            }
        }
    }
}


void CvTeamAI::AI_updateAreaStragies(bool bTargets)
{
    CvArea* pLoopArea;
    int iLoop;

    if (!(GC.getGameINLINE().isFinalInitialized()))
    {
        return;
    }

    for(pLoopArea = GC.getMapINLINE().firstArea(&iLoop); pLoopArea != NULL; pLoopArea = GC.getMapINLINE().nextArea(&iLoop))
    {
        pLoopArea->setAreaAIType(getID(), AI_calculateAreaAIType(pLoopArea));
    }

    if (bTargets)
    {
        AI_updateAreaTargets();
    }
}


void CvTeamAI::AI_updateAreaTargets()
{
    int iI;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                GET_PLAYER((PlayerTypes)iI).AI_updateAreaTargets();
            }
        }
    }
}


int CvTeamAI::AI_countFinancialTrouble() const
{
    int iCount;
    int iI;

    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (GET_PLAYER((PlayerTypes)iI).AI_isFinancialTrouble())
                {
                    iCount++;
                }
            }
        }
    }

    return iCount;
}


int CvTeamAI::AI_countMilitaryWeight(CvArea* pArea) const
{
    int iCount;
    int iI;

    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iCount += GET_PLAYER((PlayerTypes)iI).AI_militaryWeight(pArea);
            }
        }
    }

    return iCount;
}


bool CvTeamAI::AI_isAnyCapitalAreaAlone() const
{
    int iI;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (GET_PLAYER((PlayerTypes)iI).AI_isCapitalAreaAlone())
                {
                    return true;
                }
            }
        }
    }

    return false;
}


bool CvTeamAI::AI_isPrimaryArea(CvArea* pArea) const
{
    int iI;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (GET_PLAYER((PlayerTypes)iI).AI_isPrimaryArea(pArea))
                {
                    return true;
                }
            }
        }
    }

    return false;
}


bool CvTeamAI::AI_hasCitiesInPrimaryArea(TeamTypes eTeam) const
{
    CvArea* pLoopArea;
    int iLoop;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    for(pLoopArea = GC.getMapINLINE().firstArea(&iLoop); pLoopArea != NULL; pLoopArea = GC.getMapINLINE().nextArea(&iLoop))
    {
        if (AI_isPrimaryArea(pLoopArea))
        {
            if (GET_TEAM(eTeam).countNumCitiesByArea(pLoopArea))
            {
                return true;
            }
        }
    }

    return false;
}


AreaAITypes CvTeamAI::AI_calculateAreaAIType(CvArea* pArea, bool bPreparingTotal) const
{
    PROFILE_FUNC();

    bool bRecentAttack;
    bool bTargets;
    bool bChosenTargets;
    bool bDeclaredTargets;
    int iOffensiveThreshold;
    int iAreaCities;
    int iI;

    if (!(pArea->isWater()))
    {
        if (isBarbarian())
        {
            if ((pArea->getNumCities() - pArea->getCitiesPerPlayer(BARBARIAN_PLAYER)) == 0)
            {
                return AREAAI_ASSAULT;
            }
            if ((countNumAIUnitsByArea(pArea, UNITAI_ATTACK) + countNumAIUnitsByArea(pArea, UNITAI_ATTACK_CITY) + countNumAIUnitsByArea(pArea, UNITAI_PILLAGE) + countNumAIUnitsByArea(pArea, UNITAI_ATTACK_AIR)) > (((AI_countMilitaryWeight(pArea) * 20) / 100) + 1))
            {
                return AREAAI_OFFENSIVE; // XXX does this ever happen?
            }

            return AREAAI_MASSING;
        }

        bRecentAttack = false;
        bTargets = false;
        bChosenTargets = false;
        bDeclaredTargets = false;

        bool bAssault = false;
        bool bPreparingAssault = false;

        if (bPreparingTotal)
        {
            iOffensiveThreshold = 25;
        }
        else
        {
            iOffensiveThreshold = 20;
        }

        iAreaCities = countNumCitiesByArea(pArea);

        for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
        {
            if (GET_TEAM((TeamTypes)iI).isAlive())
            {
                if (AI_getWarPlan((TeamTypes)iI) != NO_WARPLAN)
                {
                    FAssert(((TeamTypes)iI) != getID());
                    FAssert(isHasMet((TeamTypes)iI) || GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_WAR));

                    if (AI_getWarPlan((TeamTypes)iI) == WARPLAN_ATTACKED_RECENT)
                    {
                        FAssert(isAtWar((TeamTypes)iI));
                        bRecentAttack = true;
                    }

                    if ((GET_TEAM((TeamTypes)iI).countNumCitiesByArea(pArea) > 0) || (GET_TEAM((TeamTypes)iI).countNumUnitsByArea(pArea) > 4))
                    {
                        bTargets = true;

                        if (AI_isChosenWar((TeamTypes)iI))
                        {
                            bChosenTargets = true;

                            if ((isAtWar((TeamTypes)iI)) ? (AI_getAtWarCounter((TeamTypes)iI) < 10) : AI_isSneakAttackReady((TeamTypes)iI))
                            {
                                bDeclaredTargets = true;
                            }
                        }
                    }
                    else
                    {
                        bAssault = true;
                        if (AI_isSneakAttackPreparing((TeamTypes)iI))
                        {
                            bPreparingAssault = true;
                        }
                    }
                }
            }
        }

        if (bDeclaredTargets)
        {
            return AREAAI_OFFENSIVE;
        }

        if (bTargets)
        {
            if ((countNumAIUnitsByArea(pArea, UNITAI_ATTACK) + countNumAIUnitsByArea(pArea, UNITAI_ATTACK_CITY) + countNumAIUnitsByArea(pArea, UNITAI_PILLAGE) + countNumAIUnitsByArea(pArea, UNITAI_ATTACK_AIR)) > (((AI_countMilitaryWeight(pArea) * iOffensiveThreshold) / 100) + 1))
            {
                return AREAAI_OFFENSIVE;
            }
        }

        if (bTargets)
        {
            for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; iPlayer++)
            {
                CvPlayerAI& kPlayer = GET_PLAYER((PlayerTypes)iI);
                if (kPlayer.isAlive())
                {
                    if (kPlayer.getTeam() == getID())
                    {
                        if (kPlayer.AI_isDoStrategy(AI_STRATEGY_DAGGER) || kPlayer.AI_isDoStrategy(AI_STRATEGY_FINAL_WAR))
                        {
                            if (pArea->getCitiesPerPlayer((PlayerTypes)iPlayer) > 0)
                            {
                                return AREAAI_MASSING;
                            }
                        }
                    }
                }
            }
            if (bRecentAttack)
            {
                int iPower = countPowerByArea(pArea);
                int iEnemyPower = countEnemyPowerByArea(pArea);
                if (iPower > iEnemyPower)
                {
                    return AREAAI_MASSING;
                }
                return AREAAI_DEFENSIVE;
            }
        }

        if (iAreaCities > 0)
        {
            if (countEnemyDangerByArea(pArea) > iAreaCities)
            {
                return AREAAI_DEFENSIVE;
            }
        }

        if (bChosenTargets)
        {
            return AREAAI_MASSING;
        }

        if (bTargets)
        {
            if (iAreaCities > (getNumMembers() * 3))
            {
                if (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) || GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_WAR) || (countPowerByArea(pArea) > ((countEnemyPowerByArea(pArea) * 3) / 2)))
                {
                    return AREAAI_MASSING;
                }
            }
            return AREAAI_DEFENSIVE;
        }
        else
        {
            if (bAssault)
            {
                if (AI_isPrimaryArea(pArea))
                {
                    if (bPreparingAssault)
                    {
                        return AREAAI_ASSAULT_MASSING;
                    }
                }
                else if (countNumCitiesByArea(pArea) > 0)
                {
                    return AREAAI_ASSAULT_ASSIST;
                }

                return AREAAI_ASSAULT;
            }
        }
    }

    return AREAAI_NEUTRAL;
}

int CvTeamAI::AI_calculateAdjacentLandPlots(TeamTypes eTeam) const
{
    CvPlot* pLoopPlot;
    int iCount;
    int iI;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    iCount = 0;

    for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
    {
        pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

        if (!(pLoopPlot->isWater()))
        {
            if ((pLoopPlot->getTeam() == eTeam) && pLoopPlot->isAdjacentTeam(getID(), true))
            {
                iCount++;
            }
        }
    }

    return iCount;
}


int CvTeamAI::AI_calculatePlotWarValue(TeamTypes eTeam) const
{
    FAssert(eTeam != getID());

    int iValue = 0;

    for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
    {
        CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

        if (pLoopPlot->getTeam() == eTeam)
        {
            if (!pLoopPlot->isWater() && pLoopPlot->isAdjacentTeam(getID(), true))
            {
                iValue += 4;
            }

            BonusTypes eBonus = pLoopPlot->getBonusType(getID());
            if (NO_BONUS != eBonus)
            {
                iValue += 40 * GC.getBonusInfo(eBonus).getAIObjective();
            }
        }
    }

    return iValue;
}


int CvTeamAI::AI_calculateCapitalProximity(TeamTypes eTeam) const
{
    CvCity* pOurCapitalCity;
    CvCity* pTheirCapitalCity;
    int iTotalDistance;
    int iCount;
    int iI, iJ;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    iTotalDistance = 0;
    iCount = 0;
 
    int iMinDistance = MAX_INT;
    int iMaxDistance = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                pOurCapitalCity = GET_PLAYER((PlayerTypes)iI).getCapitalCity();

                if (pOurCapitalCity != NULL)
                {
                    for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
                    {
                        if (GET_PLAYER((PlayerTypes)iJ).isAlive())
                        {
                            if (GET_PLAYER((PlayerTypes)iJ).getTeam() != getID())
                            {
                                pTheirCapitalCity = GET_PLAYER((PlayerTypes)iJ).getCapitalCity();

                                if (pTheirCapitalCity != NULL)
                                {
                                    int iDistance = (plotDistance(pOurCapitalCity->getX_INLINE(), pOurCapitalCity->getY_INLINE(), pTheirCapitalCity->getX_INLINE(), pTheirCapitalCity->getY_INLINE()) * (pOurCapitalCity->area() != pTheirCapitalCity->area() ? 3 : 2));
                                    if (GET_PLAYER((PlayerTypes)iJ).getTeam() == eTeam)
                                    {
                                        iTotalDistance += iDistance;
                                        iCount++;
                                    }
                                    iMinDistance = std::min(iDistance, iMinDistance);
                                    iMaxDistance = std::max(iDistance, iMaxDistance);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 
    if (iCount > 0)
    {
        FAssert(iMaxDistance > 0);
        return ((GC.getMapINLINE().maxPlotDistance() * (iMaxDistance - ((iTotalDistance / iCount) - iMinDistance))) / iMaxDistance);
    }

    return 0;
}


bool CvTeamAI::AI_isWarPossible() const
{
    if (getAtWarCount(false) > 0)
    {
        return true;
    }

    if (GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_WAR))
    {
        return true;
    }

    if (!(GC.getGameINLINE().isOption(GAMEOPTION_ALWAYS_PEACE)) && !(GC.getGameINLINE().isOption(GAMEOPTION_NO_CHANGING_WAR_PEACE)))
    {
        return true;
    }

    return false;
}


bool CvTeamAI::AI_isLandTarget(TeamTypes eTeam) const
{
    if (!AI_hasCitiesInPrimaryArea(eTeam))
    {
        return false;
    }

    if (AI_calculateAdjacentLandPlots(eTeam) < 8)
    {
        return false;
    }

    return true;
}

// this determines if eTeam or any of its allies are land targets of us
bool CvTeamAI::AI_isAllyLandTarget(TeamTypes eTeam) const
{
    for (int iTeam = 0; iTeam < MAX_CIV_TEAMS; iTeam++)
    {
        CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iTeam);
        if (iTeam != getID())
        {
            if (iTeam == eTeam || kLoopTeam.isVassal(eTeam) || GET_TEAM(eTeam).isVassal((TeamTypes)iTeam) || kLoopTeam.isDefensivePact(eTeam))
            {
                if (AI_isLandTarget((TeamTypes)iTeam))
                {
                    return true;
                }
            }
        }
    }

    return false;
}


bool CvTeamAI::AI_shareWar(TeamTypes eTeam) const
{
    int iI;

    for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
    {
        if (GET_TEAM((TeamTypes)iI).isAlive() && !GET_TEAM((TeamTypes)iI).isMinorCiv())
        {
            if ((iI != getID()) && (iI != eTeam))
            {
                if (isAtWar((TeamTypes)iI) && GET_TEAM(eTeam).isAtWar((TeamTypes)iI))
                {
                    return true;
                }
            }
        }
    }

    return false;
}


AttitudeTypes CvTeamAI::AI_getAttitude(TeamTypes eTeam, bool bForced) const
{
    int iAttitude;
    int iCount;
    int iI, iJ;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    iAttitude = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
                {
                    if (GET_PLAYER((PlayerTypes)iJ).isAlive() && iI != iJ)
                    {
                        TeamTypes eTeamLoop = GET_PLAYER((PlayerTypes)iJ).getTeam();
                        if (eTeamLoop == eTeam || GET_TEAM(eTeamLoop).isVassal(eTeam) || GET_TEAM(eTeam).isVassal(eTeamLoop))
                        {
                            iAttitude += GET_PLAYER((PlayerTypes)iI).AI_getAttitude((PlayerTypes)iJ, bForced);
                            iCount++;
                        }
                    }
                }
            }
        }
    }

    if (iCount > 0)
    {
        return ((AttitudeTypes)(iAttitude / iCount));
    }

    return ATTITUDE_CAUTIOUS;
}


int CvTeamAI::AI_getAttitudeVal(TeamTypes eTeam, bool bForced) const
{
    int iAttitudeVal;
    int iCount;
    int iI, iJ;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    iAttitudeVal = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
                {
                    if (GET_PLAYER((PlayerTypes)iJ).isAlive())
                    {
                        if (GET_PLAYER((PlayerTypes)iJ).getTeam() == eTeam)
                        {
                            iAttitudeVal += GET_PLAYER((PlayerTypes)iI).AI_getAttitudeVal((PlayerTypes)iJ, bForced);
                            iCount++;
                        }
                    }
                }
            }
        }
    }

    if (iCount > 0)
    {
        return (iAttitudeVal / iCount);
    }

    return 0;
}


int CvTeamAI::AI_getMemoryCount(TeamTypes eTeam, MemoryTypes eMemory) const
{
    int iMemoryCount;
    int iCount;
    int iI, iJ;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    iMemoryCount = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
                {
                    if (GET_PLAYER((PlayerTypes)iJ).isAlive())
                    {
                        if (GET_PLAYER((PlayerTypes)iJ).getTeam() == eTeam)
                        {
                            iMemoryCount += GET_PLAYER((PlayerTypes)iI).AI_getMemoryCount(((PlayerTypes)iJ), eMemory);
                            iCount++;
                        }
                    }
                }
            }
        }
    }

    if (iCount > 0)
    {
        return (iMemoryCount / iCount);
    }

    return 0;
}


int CvTeamAI::AI_chooseElection(const VoteSelectionData& kVoteSelectionData) const
{
    VoteSourceTypes eVoteSource = kVoteSelectionData.eVoteSource;

    FAssert(!isHuman());
    FAssert(GC.getGameINLINE().getSecretaryGeneral(eVoteSource) == getID());

    int iBestVote = -1;
    int iBestValue = 0;

    for (int iI = 0; iI < (int)kVoteSelectionData.aVoteOptions.size(); ++iI)
    {
        VoteTypes eVote = kVoteSelectionData.aVoteOptions[iI].eVote;
        CvVoteInfo& kVoteInfo = GC.getVoteInfo(eVote);

        FAssert(kVoteInfo.isVoteSourceType(eVoteSource));

        FAssert(GC.getGameINLINE().isChooseElection(eVote));
        bool bValid = true;

        if (!GC.getGameINLINE().isTeamVote(eVote))
        {
            for (int iJ = 0; iJ < MAX_PLAYERS; iJ++)
            {
                if (GET_PLAYER((PlayerTypes)iJ).isAlive())
                {
                    if (GET_PLAYER((PlayerTypes)iJ).getTeam() == getID())
                    {
                        PlayerVoteTypes eVote = GET_PLAYER((PlayerTypes)iJ).AI_diploVote(kVoteSelectionData.aVoteOptions[iI], eVoteSource, true);

                        if (eVote != PLAYER_VOTE_YES || eVote == GC.getGameINLINE().getVoteOutcome((VoteTypes)iI))
                        {
                            bValid = false;
                            break;
                        }
                    }
                }
            }
        }

        if (bValid)
        {
            int iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Choose Vote"));

            if (iValue > iBestValue)
            {
                iBestValue = iValue;
                iBestVote = iI;
            }
        }
    }

    return iBestVote;
}


int CvTeamAI::AI_startWarVal(TeamTypes eTeam) const
{
    PROFILE_FUNC();

    int iValue;

    iValue = AI_calculatePlotWarValue(eTeam);

    iValue += (3 * AI_calculateCapitalProximity(eTeam)) / ((iValue > 0) ? 2 : 3);
 
    int iClosenessValue = AI_teamCloseness(eTeam);
    if (iClosenessValue == 0)
    {
        iValue /= (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 4 : 2);
    }
    iValue += iClosenessValue;
 
    int iOurVictoryCountdown = AI_getLowestVictoryCountdown();
    int iTheirVictoryCountdown = GET_TEAM(eTeam).AI_getLowestVictoryCountdown();
 
    if ((iTheirVictoryCountdown != -1) && ((iOurVictoryCountdown == -1) || iTheirVictoryCountdown < iOurVictoryCountdown))
    {
        iValue ++;
        iValue *= 8;
    }

    //Domination...
    int iOurLandPercent = getTotalLand(true) * 100 / GC.getMapINLINE().getLandPlots();
    int iPercentOfDomination = 0;
    for (int iI = 0; iI < GC.getNumVictoryInfos(); iI++)
    {
        if (GC.getVictoryInfo((VictoryTypes)iI).getLandPercent() > 0)
        {
            iPercentOfDomination = 100 * iOurLandPercent / std::max(1, GC.getGameINLINE().getAdjustedLandPercent((VictoryTypes)iI));
        }
    }
 
    if (iPercentOfDomination > 75)
    {
        iValue *= (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 6 : 4);
    }

    switch (AI_getAttitude(eTeam))
    {
    case ATTITUDE_FURIOUS:
        iValue *= 16;
        break;

    case ATTITUDE_ANNOYED:
        iValue *= 8;
        break;

    case ATTITUDE_CAUTIOUS:
        iValue *= 4;
        break;

    case ATTITUDE_PLEASED:
        iValue *= 2;
        break;

    case ATTITUDE_FRIENDLY:
        iValue *= 1;
        break;

    default:
        FAssert(false);
        break;
    }
 
    int iMaxCultureVictoryAdjustment = 1;
    for (int iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if  (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if  (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_CULTURE3))
                {
                    iMaxCultureVictoryAdjustment = std::max(iMaxCultureVictoryAdjustment, 8);
                }
                else if  (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_CULTURE2))
                {
                    iMaxCultureVictoryAdjustment = std::max(iMaxCultureVictoryAdjustment, 3);
                }
            }
        }
    }
    iValue /= iMaxCultureVictoryAdjustment;

    return iValue;
}


// XXX this should consider area power...
int CvTeamAI::AI_endWarVal(TeamTypes eTeam) const
{
    int iValue;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(isAtWar(eTeam), "Current AI Team instance is expected to be at war with eTeam");

    iValue = 100;

    iValue += (getNumCities() * 3);
    iValue += (GET_TEAM(eTeam).getNumCities() * 3);

    iValue += getTotalPopulation();
    iValue += GET_TEAM(eTeam).getTotalPopulation();

    iValue += (GET_TEAM(eTeam).AI_getWarSuccess(getID()) * 20);

    int iOurPower = std::max(1, getPower(true));
    int iTheirPower = std::max(1, GET_TEAM(eTeam).getDefensivePower());

    iValue *= iTheirPower + 10;
    iValue /= std::max(1, iOurPower + iTheirPower + 10);
 
    WarPlanTypes eWarPlan = AI_getWarPlan(eTeam);

    // if we not human, do we want to continue war for strategic reasons?
    // only check if our power is at least 120% of theirs
    if (!isHuman() && iOurPower > ((120 * iTheirPower) / 100))
    {
        bool bDagger = false;
   
        bool bAnyFinancialTrouble = false;
        for (int iI = 0; iI < MAX_PLAYERS; iI++)
        {
            if (GET_PLAYER((PlayerTypes)iI).isAlive())
            {
                if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
                {
                    if (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_DAGGER))
                    {
                        bDagger = true;
                    }
               
                    if (GET_PLAYER((PlayerTypes)iI).AI_isFinancialTrouble())
                    {
                        bAnyFinancialTrouble = true;
                    }
                }
            }
        }
   
        // if dagger, value peace at 90% * power ratio
        if (bDagger)
        {
            iValue *= 9 * iTheirPower;
            iValue /= 10 * iOurPower;
        }
   
        // for now, we will always do the land mass check for domination
        // if we have more than half the land, then value peace at 90% * land ratio
        int iLandRatio = ((getTotalLand(true) * 100) / std::max(1, GET_TEAM(eTeam).getTotalLand(true)));
        if (iLandRatio > 120)
        {
            iValue *= 9 * 100;
            iValue /= 10 * iLandRatio;
        }

        // if in financial trouble, warmongers will continue the fight to make more money
        if (bAnyFinancialTrouble)
        {
            switch (eWarPlan)
            {
                case WARPLAN_TOTAL:
                    // if we total warmonger, value peace at 70% * power ratio factor
                    if (bDagger || AI_maxWarRand() < 100)
                    {
                        iValue *= 7 * (5 * iTheirPower);
                        iValue /= 10 * (iOurPower + (4 * iTheirPower));
                    }
                    break;

                case WARPLAN_LIMITED:
                    // if we limited warmonger, value peace at 70% * power ratio factor
                    if (AI_limitedWarRand() < 100)
                    {
                        iValue *= 7 * (5 * iTheirPower);
                        iValue /= 10 * (iOurPower + (4 * iTheirPower));
                    }
                    break;

                case WARPLAN_DOGPILE:
                    // if we dogpile warmonger, value peace at 70% * power ratio factor
                    if (AI_dogpileWarRand() < 100)
                    {
                        iValue *= 7 * (5 * iTheirPower);
                        iValue /= 10 * (iOurPower + (4 * iTheirPower));
                    }
                    break;

            }
        }
    }


    // XXX count units in enemy territory...

    if ((!(isHuman()) && (eWarPlan == WARPLAN_TOTAL)) ||
          (!(GET_TEAM(eTeam).isHuman()) && (GET_TEAM(eTeam).AI_getWarPlan(getID()) == WARPLAN_TOTAL)))
    {
        iValue *= 2;
    }
    else if ((!(isHuman()) && (eWarPlan == WARPLAN_DOGPILE) && (GET_TEAM(eTeam).getAtWarCount(true) > 1)) ||
               (!(GET_TEAM(eTeam).isHuman()) && (GET_TEAM(eTeam).AI_getWarPlan(getID()) == WARPLAN_DOGPILE) && (getAtWarCount(true) > 1)))
    {
        iValue *= 3;
        iValue /= 2;
    }

    if (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
    {
        int iOurEndangeredCities = 0;
        int iTheirEndangeredCities = 0;
   
        for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; iPlayer++)
        {
            CvPlayer& kPlayer = GET_PLAYER((PlayerTypes)iPlayer);
       
            if (kPlayer.getTeam() == eTeam)
            {
                int iLoop;
                CvCity* pTheirLoopCity;
           
                for (pTheirLoopCity = kPlayer.firstCity(&iLoop); pTheirLoopCity != NULL; pTheirLoopCity = kPlayer.nextCity(&iLoop))
                {
                    if (pTheirLoopCity->AI_isDanger())
                    {
                        iTheirEndangeredCities++;
                    }
                }
            }

            if (kPlayer.getTeam() == getID())
            {
                int iLoop;
                CvCity* pOurLoopCity;
           
                for (pOurLoopCity = kPlayer.firstCity(&iLoop); pOurLoopCity != NULL; pOurLoopCity = kPlayer.nextCity(&iLoop))
                {
                    if (pOurLoopCity->AI_isDanger())
                    {
                        iOurEndangeredCities++;
                    }
                }
            }
        }

        if (iTheirEndangeredCities > iOurEndangeredCities)
        {
            iValue /= 3;
        }
    }

    iValue -= (iValue % GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));

    if (isHuman())
    {
        return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
    }
    else
    {
        return iValue;
    }
}


int CvTeamAI::AI_techTradeVal(TechTypes eTech, TeamTypes eTeam) const
{
    FAssert(eTeam != getID());
    int iKnownCount;
    int iPossibleKnownCount;
    int iCost;
    int iValue;
    int iI;

    iCost = std::max(0, (getResearchCost(eTech) - getResearchProgress(eTech)));

    iValue = ((iCost * 3) / 2);

    iKnownCount = 0;
    iPossibleKnownCount = 0;

    for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
    {
        if (GET_TEAM((TeamTypes)iI).isAlive())
        {
            if (iI != getID())
            {
                if (isHasMet((TeamTypes)iI))
                {
                    if (GET_TEAM((TeamTypes)iI).isHasTech(eTech))
                    {
                        iKnownCount++;
                    }

                    iPossibleKnownCount++;
                }
            }
        }
    }

    iValue += (((iCost / 2) * (iPossibleKnownCount - iKnownCount)) / iPossibleKnownCount);

    iValue *= std::max(0, (GC.getTechInfo(eTech).getAITradeModifier() + 100));
    iValue /= 100;

    iValue -= (iValue % GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));

    if (isHuman())
    {
        return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
    }
    else
    {
        return iValue;
    }
}


DenialTypes CvTeamAI::AI_techTrade(TechTypes eTech, TeamTypes eTeam) const
{
    PROFILE_FUNC();

    AttitudeTypes eAttitude;
    int iNoTechTradeThreshold;
    int iTechTradeKnownPercent;
    int iKnownCount;
    int iPossibleKnownCount;
    int iI, iJ;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
 
 
    if (GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_BROKERING))
    {
        CvTeam& kTeam = GET_TEAM(eTeam);
   
        if (!kTeam.isHasTech(eTech))
        {
            if (!kTeam.isHuman())
            {
                if (2 * kTeam.getResearchProgress(eTech) > kTeam.getResearchCost(eTech))
                {
                    return DENIAL_NO_GAIN;
                }
            }
        }
    }
 
    if (isHuman())
    {
        return NO_DENIAL;
    }

    if (isVassal(eTeam))
    {
        return NO_DENIAL;
    }

    if (isAtWar(eTeam))
    {
        return NO_DENIAL;
    }

    if (AI_getWorstEnemy() == eTeam)
    {
        return DENIAL_WORST_ENEMY;
    }

    eAttitude = AI_getAttitude(eTeam);

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (eAttitude <= GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getTechRefuseAttitudeThreshold())
                {
                    return DENIAL_ATTITUDE;
                }
            }
        }
    }

    if (eAttitude < ATTITUDE_FRIENDLY)
    {
        if ((GC.getGameINLINE().getTeamRank(getID()) < (GC.getGameINLINE().countCivTeamsEverAlive() / 2)) ||
              (GC.getGameINLINE().getTeamRank(eTeam) < (GC.getGameINLINE().countCivTeamsEverAlive() / 2)))
        {
            iNoTechTradeThreshold = AI_noTechTradeThreshold();

            iNoTechTradeThreshold *= std::max(0, (GC.getHandicapInfo(GET_TEAM(eTeam).getHandicapType()).getNoTechTradeModifier() + 100));
            iNoTechTradeThreshold /= 100;

            if (AI_getMemoryCount(eTeam, MEMORY_RECEIVED_TECH_FROM_ANY) > iNoTechTradeThreshold)
            {
                return DENIAL_TECH_WHORE;
            }
        }

        iKnownCount = 0;
        iPossibleKnownCount = 0;

        for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
        {
            if (GET_TEAM((TeamTypes)iI).isAlive())
            {
                if ((iI != getID()) && (iI != eTeam))
                {
                    if (isHasMet((TeamTypes)iI))
                    {
                        if (GET_TEAM((TeamTypes)iI).isHasTech(eTech))
                        {
                            iKnownCount++;
                        }

                        iPossibleKnownCount++;
                    }
                }
            }
        }

        iTechTradeKnownPercent = AI_techTradeKnownPercent();

        iTechTradeKnownPercent *= std::max(0, (GC.getHandicapInfo(GET_TEAM(eTeam).getHandicapType()).getTechTradeKnownModifier() + 100));
        iTechTradeKnownPercent /= 100;
   
        iTechTradeKnownPercent *= AI_getTechMonopolyValue(eTech, eTeam);
        iTechTradeKnownPercent /= 100;

        if ((iPossibleKnownCount > 0) ? (((iKnownCount * 100) / iPossibleKnownCount) < iTechTradeKnownPercent) : (iTechTradeKnownPercent > 0))
        {
            return DENIAL_TECH_MONOPOLY;
        }
    }

    for (iI = 0; iI < GC.getNumUnitInfos(); iI++)
    {
        if (isTechRequiredForUnit(eTech, ((UnitTypes)iI)))
        {
            if (isWorldUnitClass((UnitClassTypes)(GC.getUnitInfo((UnitTypes)iI).getUnitClassType())))
            {
                if (getUnitClassMaking((UnitClassTypes)(GC.getUnitInfo((UnitTypes)iI).getUnitClassType())) > 0)
                {
                    return DENIAL_MYSTERY;
                }
            }
        }
    }

    for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
    {
        if (isTechRequiredForBuilding(eTech, ((BuildingTypes)iI)))
        {
            if (isWorldWonderClass((BuildingClassTypes)(GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType())))
            {
                if (getBuildingClassMaking((BuildingClassTypes)(GC.getBuildingInfo((BuildingTypes)iI).getBuildingClassType())) > 0)
                {
                    return DENIAL_MYSTERY;
                }
            }
        }
    }

    for (iI = 0; iI < GC.getNumProjectInfos(); iI++)
    {
        if (GC.getProjectInfo((ProjectTypes)iI).getTechPrereq() == eTech)
        {
            if (isWorldProject((ProjectTypes)iI))
            {
                if (getProjectMaking((ProjectTypes)iI) > 0)
                {
                    return DENIAL_MYSTERY;
                }
            }

            for (iJ = 0; iJ < GC.getNumVictoryInfos(); iJ++)
            {
                if (GC.getGameINLINE().isVictoryValid((VictoryTypes)iJ))
                {
                    if (GC.getProjectInfo((ProjectTypes)iI).getVictoryThreshold((VictoryTypes)iJ))
                    {
                        return DENIAL_VICTORY;
                    }
                }
            }
        }
    }

    return NO_DENIAL;
}


int CvTeamAI::AI_mapTradeVal(TeamTypes eTeam) const
{
    CvPlot* pLoopPlot;
    int iValue;
    int iI;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    iValue = 0;

    for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
    {
        pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

        if (!(pLoopPlot->isRevealed(getID(), false)) && pLoopPlot->isRevealed(eTeam, false))
        {
            if (pLoopPlot->isWater())
            {
                iValue++;
            }
            else
            {
                iValue += 5;
            }
        }
    }

    iValue /= 10;

    if (GET_TEAM(eTeam).isVassal(getID()))
    {
        iValue /= 2;
    }

    iValue -= (iValue % GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));

    if (isHuman())
    {
        return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
    }
    else
    {
        return iValue;
    }
}


DenialTypes CvTeamAI::AI_mapTrade(TeamTypes eTeam) const
{
    PROFILE_FUNC();

    AttitudeTypes eAttitude;
    int iI;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    if (isHuman())
    {
        return NO_DENIAL;
    }

    if (isVassal(eTeam))
    {
        return NO_DENIAL;
    }

    if (isAtWar(eTeam))
    {
        return NO_DENIAL;
    }

    if (AI_getWorstEnemy() == eTeam)
    {
        return DENIAL_WORST_ENEMY;
    }

    eAttitude = AI_getAttitude(eTeam);

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (eAttitude <= GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getMapRefuseAttitudeThreshold())
                {
                    return DENIAL_ATTITUDE;
                }
            }
        }
    }

    return NO_DENIAL;
}


int CvTeamAI::AI_vassalTradeVal(TeamTypes eTeam) const
{
    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    return AI_surrenderTradeVal(eTeam);
}


DenialTypes CvTeamAI::AI_vassalTrade(TeamTypes eTeam) const
{
    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    CvTeamAI& kMasterTeam = GET_TEAM(eTeam);

    for (int iLoopTeam = 0; iLoopTeam < MAX_TEAMS; iLoopTeam++)
    {
        CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iLoopTeam);
        if (kLoopTeam.isAlive() && iLoopTeam != getID() && iLoopTeam != kMasterTeam.getID())
        {
            if (!kLoopTeam.isAtWar(kMasterTeam.getID()) && kLoopTeam.isAtWar(getID()))
            {
                if (kMasterTeam.isForcePeace((TeamTypes)iLoopTeam) || !kMasterTeam.canChangeWarPeace((TeamTypes)iLoopTeam))
                {
                    if (!kLoopTeam.isAVassal())
                    {
                        return DENIAL_WAR_NOT_POSSIBLE_YOU;
                    }
                }

                if (!kMasterTeam.isHuman())
                {
                    DenialTypes eWarDenial = kMasterTeam.AI_declareWarTrade((TeamTypes)iLoopTeam, getID(), true);
                    if (NO_DENIAL != eWarDenial)
                    {
                        return DENIAL_WAR_NOT_POSSIBLE_YOU;
                    }
                }
            }
            else if (kLoopTeam.isAtWar(kMasterTeam.getID()) && !kLoopTeam.isAtWar(getID()))
            {
                if (!kMasterTeam.canChangeWarPeace((TeamTypes)iLoopTeam))
                {
                    if (!kLoopTeam.isAVassal())
                    {
                        return DENIAL_PEACE_NOT_POSSIBLE_YOU;
                    }
                }

                if (!kMasterTeam.isHuman())
                {
                    DenialTypes ePeaceDenial = kMasterTeam.AI_makePeaceTrade((TeamTypes)iLoopTeam, getID());
                    if (NO_DENIAL != ePeaceDenial)
                    {
                        return DENIAL_PEACE_NOT_POSSIBLE_YOU;
                    }
                }
            }
        }
    }

    return AI_surrenderTrade(eTeam);
}


int CvTeamAI::AI_surrenderTradeVal(TeamTypes eTeam) const
{
    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    return 0;
}


DenialTypes CvTeamAI::AI_surrenderTrade(TeamTypes eTeam, int iPowerMultiplier) const
{
    PROFILE_FUNC();

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    CvTeam& kMasterTeam = GET_TEAM(eTeam);

    for (int iLoopTeam = 0; iLoopTeam < MAX_TEAMS; iLoopTeam++)
    {
        CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iLoopTeam);
        if (kLoopTeam.isAlive() && iLoopTeam != getID() && iLoopTeam != kMasterTeam.getID())
        {
            if (kLoopTeam.isAtWar(kMasterTeam.getID()) && !kLoopTeam.isAtWar(getID()))
            {
                if (isForcePeace((TeamTypes)iLoopTeam) || !canChangeWarPeace((TeamTypes)iLoopTeam))
                {
                    if (!kLoopTeam.isAVassal())
                    {
                        return DENIAL_WAR_NOT_POSSIBLE_US;
                    }
                }
            }
            else if (!kLoopTeam.isAtWar(kMasterTeam.getID()) && kLoopTeam.isAtWar(getID()))
            {
                if (!canChangeWarPeace((TeamTypes)iLoopTeam))
                {
                    if (!kLoopTeam.isAVassal())
                    {
                        return DENIAL_PEACE_NOT_POSSIBLE_US;
                    }
                }
            }
        }
    }

    if (isHuman())
    {
        return NO_DENIAL;
    }

    int iAttitudeModifier = 0;

    if (!GET_TEAM(eTeam).isParent(getID()))
    {
        int iPersonalityModifier = 0;
        int iMembers = 0;
        for (int iI = 0; iI < MAX_PLAYERS; iI++)
        {
            if (GET_PLAYER((PlayerTypes)iI).isAlive())
            {
                if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
                {
                    iPersonalityModifier += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getVassalPowerModifier();
                    ++iMembers;
                }
            }
        }

        int iTotalPower = GC.getGameINLINE().countTotalCivPower();
        int iAveragePower = iTotalPower / std::max(1, GC.getGameINLINE().countCivTeamsAlive());
        int iMasterPower = GET_TEAM(eTeam).getPower(false);
        int iVassalPower = (getPower(true) * (iPowerMultiplier + iPersonalityModifier / std::max(1, iMembers))) / 100;

        if (isAtWar(eTeam))
        {
            int iTheirSuccess = std::max(10, GET_TEAM(eTeam).AI_getWarSuccess(getID()));
            int iOurSuccess = std::max(10, AI_getWarSuccess(eTeam));
            int iOthersBestSuccess = 0;
            for (int iTeam = 0; iTeam < MAX_CIV_TEAMS; ++iTeam)
            {
                if (iTeam != eTeam && iTeam != getID())
                {
                    CvTeam& kLoopTeam = GET_TEAM((TeamTypes)iTeam);

                    if (kLoopTeam.isAlive() && kLoopTeam.isAtWar(getID()))
                    {
                        int iSuccess = kLoopTeam.AI_getWarSuccess(getID());
                        if (iSuccess > iOthersBestSuccess)
                        {
                            iOthersBestSuccess = iSuccess;
                        }
                    }
                }
            }

            // Discourage capitulation to a team that has not done the most damage
            if (iTheirSuccess < iOthersBestSuccess)
            {
                iOurSuccess += iOthersBestSuccess - iTheirSuccess;
            }

            iMasterPower = (2 * iMasterPower * iTheirSuccess) / (iTheirSuccess + iOurSuccess);

            if (AI_getWorstEnemy() == eTeam)
            {
                iMasterPower *= 3;
                iMasterPower /= 4;
            }
        }
        else
        {
            if (!GET_TEAM(eTeam).AI_isLandTarget(getID()))
            {
                iMasterPower /= 2;
            }
        }


        for (int iLoopTeam = 0; iLoopTeam < MAX_CIV_TEAMS; iLoopTeam++)
        {
            if (iLoopTeam != getID())
            {
                CvTeamAI& kLoopTeam = GET_TEAM((TeamTypes)iLoopTeam);

                if (kLoopTeam.isAlive())
                {
                    if (kLoopTeam.AI_isLandTarget(getID()))
                    {
                        if (iLoopTeam != eTeam)
                        {
                            if (kLoopTeam.getPower(true) > getPower(true))
                            {
                                if (kLoopTeam.isAtWar(eTeam) && !kLoopTeam.isAtWar(getID()))
                                {
                                    return DENIAL_POWER_YOUR_ENEMIES;
                                }

                                iAveragePower = (2 * iAveragePower * kLoopTeam.getPower(true)) / std::max(1, kLoopTeam.getPower(true) + getPower(true));

                                iAttitudeModifier += (3 * kLoopTeam.getPower(true)) / std::max(1, getPower(true)) - 2;
                            }

                            if (!kLoopTeam.isAtWar(eTeam) && kLoopTeam.isAtWar(getID()))
                            {
                                iAveragePower = (iAveragePower * (getPower(true) + GET_TEAM(eTeam).getPower(false))) / std::max(1, getPower(true));
                            }
                        }
                    }

                    if (!atWar(getID(), eTeam))
                    {
                        if (kLoopTeam.isAtWar(eTeam) && !kLoopTeam.isAtWar(getID()))
                        {
                            DenialTypes eDenial = AI_declareWarTrade((TeamTypes)iLoopTeam, eTeam, false);
                            if (eDenial != NO_DENIAL)
                            {
                                return eDenial;
                            }
                        }
                    }
                }
            }
        }

        if (!isVassal(eTeam) && canVassalRevolt(eTeam))
        {
            return DENIAL_POWER_US;
        }

        if (iVassalPower > iAveragePower || 3 * iVassalPower > 2 * iMasterPower)
        {
            return DENIAL_POWER_US;
        }

        for (int i = 0; i < GC.getNumVictoryInfos(); i++)
        {
            bool bPopulationThreat = true;
            if (GC.getGameINLINE().getAdjustedPopulationPercent((VictoryTypes)i) > 0)
            {
                bPopulationThreat = false;

                int iThreshold = GC.getGameINLINE().getTotalPopulation() * GC.getGameINLINE().getAdjustedPopulationPercent((VictoryTypes)i);
                if (400 * getTotalPopulation(!isAVassal()) > 3 * iThreshold)
                {
                    return DENIAL_VICTORY;
                }

                if (!atWar(getID(), eTeam))
                {
                    if (400 * (getTotalPopulation(isAVassal()) + GET_TEAM(eTeam).getTotalPopulation()) > 3 * iThreshold)
                    {
                        bPopulationThreat = true;
                    }
                }
            }

            bool bLandThreat = true;
            if (GC.getGameINLINE().getAdjustedLandPercent((VictoryTypes)i) > 0)
            {
                bLandThreat = false;

                int iThreshold = GC.getMapINLINE().getLandPlots() * GC.getGameINLINE().getAdjustedLandPercent((VictoryTypes)i);
                if (400 * getTotalLand(!isAVassal()) > 3 * iThreshold)
                {
                    return DENIAL_VICTORY;
                }

                if (!atWar(getID(), eTeam))
                {
                    if (400 * (getTotalLand(isAVassal()) + GET_TEAM(eTeam).getTotalLand()) > 3 * iThreshold)
                    {
                        bLandThreat = true;
                    }
                }
            }

            if (GC.getGameINLINE().getAdjustedPopulationPercent((VictoryTypes)i) > 0 || GC.getGameINLINE().getAdjustedLandPercent((VictoryTypes)i) > 0)
            {
                if (bLandThreat && bPopulationThreat)
                {
                    return DENIAL_POWER_YOU;
                }
            }
        }
    }

    if (!isAtWar(eTeam))
    {
        if (!GET_TEAM(eTeam).isParent(getID()))
        {
            if (AI_getWorstEnemy() == eTeam)
            {
                return DENIAL_WORST_ENEMY;
            }

            if (!AI_hasCitiesInPrimaryArea(eTeam) && AI_calculateAdjacentLandPlots(eTeam) == 0)
            {
                return DENIAL_TOO_FAR;
            }
        }

        AttitudeTypes eAttitude = AI_getAttitude(eTeam, false);

        AttitudeTypes eModifiedAttitude = CvPlayerAI::AI_getAttitudeFromValue(AI_getAttitudeVal(eTeam, false) + iAttitudeModifier);

        for (int iI = 0; iI < MAX_PLAYERS; iI++)
        {
            if (GET_PLAYER((PlayerTypes)iI).isAlive())
            {
                if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
                {
                    if (eAttitude <= ATTITUDE_FURIOUS)
                    {
                        return DENIAL_ATTITUDE;
                    }

                    if (eModifiedAttitude <= GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getVassalRefuseAttitudeThreshold())
                    {
                        return DENIAL_ATTITUDE;
                    }
                }
            }
        }
    }
    else
    {
        if (AI_getWarSuccess(eTeam) + 4 * GC.getDefineINT("WAR_SUCCESS_CITY_CAPTURING") > GET_TEAM(eTeam).AI_getWarSuccess(getID()))
        {
            return DENIAL_JOKING;
        }
    }
 
    return NO_DENIAL;
}


int CvTeamAI::AI_makePeaceTradeVal(TeamTypes ePeaceTeam, TeamTypes eTeam) const
{
    int iModifier;
    int iValue;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(ePeaceTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(GET_TEAM(ePeaceTeam).isAlive(), "GET_TEAM(ePeaceTeam).isAlive is expected to be true");
    FAssertMsg(atWar(ePeaceTeam, eTeam), "eTeam should be at war with ePeaceTeam");

    iValue = (50 + GC.getGameINLINE().getGameTurn());
    iValue += ((GET_TEAM(eTeam).getNumCities() + GET_TEAM(ePeaceTeam).getNumCities()) * 8);

    iModifier = 0;

    switch ((GET_TEAM(eTeam).AI_getAttitude(ePeaceTeam) + GET_TEAM(ePeaceTeam).AI_getAttitude(eTeam)) / 2)
    {
    case ATTITUDE_FURIOUS:
        iModifier += 400;
        break;

    case ATTITUDE_ANNOYED:
        iModifier += 200;
        break;

    case ATTITUDE_CAUTIOUS:
        iModifier += 100;
        break;

    case ATTITUDE_PLEASED:
        iModifier += 50;
        break;

    case ATTITUDE_FRIENDLY:
        break;

    default:
        FAssert(false);
        break;
    }

    iValue *= std::max(0, (iModifier + 100));
    iValue /= 100;

    iValue *= 40;
    iValue /= (GET_TEAM(eTeam).AI_getAtWarCounter(ePeaceTeam) + 10);

    iValue -= (iValue % GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));

    if (isHuman())
    {
        return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
    }
    else
    {
        return iValue;
    }
}


DenialTypes CvTeamAI::AI_makePeaceTrade(TeamTypes ePeaceTeam, TeamTypes eTeam) const
{
    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(ePeaceTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(GET_TEAM(ePeaceTeam).isAlive(), "GET_TEAM(ePeaceTeam).isAlive is expected to be true");
    FAssertMsg(isAtWar(ePeaceTeam), "should be at war with ePeaceTeam");

    if (GET_TEAM(ePeaceTeam).isHuman())
    {
        return DENIAL_CONTACT_THEM;
    }

    if (GET_TEAM(ePeaceTeam).isAVassal())
    {
        return DENIAL_VASSAL;
    }

    if (isHuman())
    {
        return NO_DENIAL;
    }

    if (!canChangeWarPeace(ePeaceTeam))
    {
        return DENIAL_VASSAL;
    }

    if (AI_endWarVal(ePeaceTeam) > (GET_TEAM(ePeaceTeam).AI_endWarVal(getID()) * 2))
    {
        return DENIAL_CONTACT_THEM;
    }
 
    int iLandRatio = ((getTotalLand(true) * 100) / std::max(20, GET_TEAM(eTeam).getTotalLand(true)));
    if (iLandRatio > 250)
    {
        return DENIAL_VICTORY;
    }

    return NO_DENIAL;
}


int CvTeamAI::AI_declareWarTradeVal(TeamTypes eWarTeam, TeamTypes eTeam) const
{
    PROFILE_FUNC();

    int iModifier;
    int iValue;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(eWarTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(GET_TEAM(eWarTeam).isAlive(), "GET_TEAM(eWarTeam).isAlive is expected to be true");
    FAssertMsg(!atWar(eWarTeam, eTeam), "eTeam should be at peace with eWarTeam");

    iValue = 0;
    iValue += (GET_TEAM(eWarTeam).getNumCities() * 10);
    iValue += (GET_TEAM(eWarTeam).getTotalPopulation(true) * 2);

    iModifier = 0;

    switch (GET_TEAM(eTeam).AI_getAttitude(eWarTeam))
    {
    case ATTITUDE_FURIOUS:
        break;

    case ATTITUDE_ANNOYED:
        iModifier += 25;
        break;

    case ATTITUDE_CAUTIOUS:
        iModifier += 50;
        break;

    case ATTITUDE_PLEASED:
        iModifier += 150;
        break;

    case ATTITUDE_FRIENDLY:
        iModifier += 400;
        break;

    default:
        FAssert(false);
        break;
    }

    iValue *= std::max(0, (iModifier + 100));
    iValue /= 100;

    int iTheirPower = GET_TEAM(eTeam).getPower(true);
    int iWarTeamPower = GET_TEAM(eWarTeam).getPower(true);

    iValue *= 50 + ((100 * iWarTeamPower) / (iTheirPower + iWarTeamPower + 1));
    iValue /= 100;

    if (!(GET_TEAM(eTeam).AI_isAllyLandTarget(eWarTeam)))
    {
        iValue *= 2;
    }

    if (!isAtWar(eWarTeam))
    {
        iValue *= 3;
    }
    else
    {
        iValue *= 150;
        iValue /= 100 + ((50 * std::min(100, (100 * AI_getWarSuccess(eWarTeam)) / (8 + getTotalPopulation(false)))) / 100);
    }
 
    iValue += (GET_TEAM(eTeam).getNumCities() * 20);
    iValue += (GET_TEAM(eTeam).getTotalPopulation(true) * 15);
 
    if (isAtWar(eWarTeam))
    {
        switch (GET_TEAM(eTeam).AI_getAttitude(getID()))
        {
        case ATTITUDE_FURIOUS:
        case ATTITUDE_ANNOYED:
        case ATTITUDE_CAUTIOUS:
            iValue *= 100;
            break;

        case ATTITUDE_PLEASED:
            iValue *= std::max(75, 100 - getAtWarCount(true) * 10);
            break;

        case ATTITUDE_FRIENDLY:
            iValue *= std::max(50, 100 - getAtWarCount(true) * 20);
            break;

        default:
            FAssert(false);
            break;
        }
        iValue /= 100;
    }
 
    iValue += GET_TEAM(eWarTeam).getNumNukeUnits() * 250;//Don't want to get nuked
    iValue += GET_TEAM(eTeam).getNumNukeUnits() * 150;//Don't want to use nukes on another's behalf

    if (GET_TEAM(eWarTeam).getAtWarCount(false) == 0)
    {
        iValue *= 2;
 
        for (int iI = 0; iI < MAX_CIV_TEAMS; iI++)
        {
            if (GET_TEAM((TeamTypes)iI).isAlive())
            {
                if (iI != getID() && iI != eWarTeam && iI != eTeam)
                {
                    if (GET_TEAM(eWarTeam).isDefensivePact((TeamTypes)iI))
                    {
                        iValue += (GET_TEAM((TeamTypes)iI).getNumCities() * 30);
                        iValue += (GET_TEAM((TeamTypes)iI).getTotalPopulation(true) * 20);
                    }
                }
            }
        }
    }

    iValue *= 60 + (140 * GC.getGameINLINE().getGameTurn()) / std::max(1, GC.getGameINLINE().getEstimateEndTurn());
    iValue /= 100;

    iValue -= (iValue % GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));

    if (isHuman())
    {
        return std::max(iValue, GC.getDefineINT("DIPLOMACY_VALUE_REMAINDER"));
    }
    else
    {
        return iValue;
    }
}


DenialTypes CvTeamAI::AI_declareWarTrade(TeamTypes eWarTeam, TeamTypes eTeam, bool bConsiderPower) const
{
    PROFILE_FUNC();

    AttitudeTypes eAttitude;
    AttitudeTypes eAttitudeThem;
    bool bLandTarget;
    int iI;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(eWarTeam != getID(), "shouldn't call this function on ourselves");
    FAssertMsg(GET_TEAM(eWarTeam).isAlive(), "GET_TEAM(eWarTeam).isAlive is expected to be true");
    FAssertMsg(!isAtWar(eWarTeam), "should be at peace with eWarTeam");

    if (GET_TEAM(eWarTeam).isVassal(eTeam) || GET_TEAM(eWarTeam).isDefensivePact(eTeam))
    {
        return DENIAL_JOKING;
    }

    if (isHuman())
    {
        return NO_DENIAL;
    }

    if (!canDeclareWar(eWarTeam))
    {
        return DENIAL_VASSAL;
    }

    if (getAnyWarPlanCount(true) > 0)
    {
        return DENIAL_TOO_MANY_WARS;
    }

    if (bConsiderPower)
    {
        bLandTarget = AI_isAllyLandTarget(eWarTeam);

        if ((GET_TEAM(eWarTeam).getDefensivePower() / ((bLandTarget) ? 2 : 1)) >
            (getPower(true) + ((atWar(eWarTeam, eTeam)) ? GET_TEAM(eTeam).getPower(true) : 0)))
        {
            if (bLandTarget)
            {
                return DENIAL_POWER_THEM;
            }
            else
            {
                return DENIAL_NO_GAIN;
            }
        }
    }

    eAttitude = AI_getAttitude(eTeam);

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (eAttitude <= GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getDeclareWarRefuseAttitudeThreshold())
                {
                    return DENIAL_ATTITUDE;
                }
            }
        }
    }

    eAttitudeThem = AI_getAttitude(eWarTeam);

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (eAttitudeThem > GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getDeclareWarThemRefuseAttitudeThreshold())
                {
                    return DENIAL_ATTITUDE_THEM;
                }
            }
        }
    }
 
    if (!atWar(eWarTeam, eTeam))
    {
        if (GET_TEAM(eWarTeam).getNumNukeUnits() > 0)
        {
            return DENIAL_JOKING;
        }
    }

    return NO_DENIAL;
}


int CvTeamAI::AI_openBordersTradeVal(TeamTypes eTeam) const
{
    return (getNumCities() + GET_TEAM(eTeam).getNumCities());
}


DenialTypes CvTeamAI::AI_openBordersTrade(TeamTypes eTeam) const
{
    PROFILE_FUNC();

    AttitudeTypes eAttitude;
    int iI;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    if (isHuman())
    {
        return NO_DENIAL;
    }

    if (isVassal(eTeam))
    {
        return NO_DENIAL;
    }

    if (AI_shareWar(eTeam))
    {
        return NO_DENIAL;
    }
 
    if (AI_getMemoryCount(eTeam, MEMORY_CANCELLED_OPEN_BORDERS) > 0)
    {
        return DENIAL_RECENT_CANCEL;
    }

    if (AI_getWorstEnemy() == eTeam)
    {
        return DENIAL_WORST_ENEMY;
    }

    eAttitude = AI_getAttitude(eTeam);

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (eAttitude <= GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getOpenBordersRefuseAttitudeThreshold())
                {
                    return DENIAL_ATTITUDE;
                }
            }
        }
    }

    return NO_DENIAL;
}


int CvTeamAI::AI_defensivePactTradeVal(TeamTypes eTeam) const
{
    return ((getNumCities() + GET_TEAM(eTeam).getNumCities()) * 3);
}


DenialTypes CvTeamAI::AI_defensivePactTrade(TeamTypes eTeam) const
{
    PROFILE_FUNC();

    AttitudeTypes eAttitude;
    int iI;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    if (isHuman())
    {
        return NO_DENIAL;
    }

    if (GC.getGameINLINE().countCivTeamsAlive() == 2)
    {
        return DENIAL_NO_GAIN;
    }

    if (AI_getWorstEnemy() == eTeam)
    {
        return DENIAL_WORST_ENEMY;
    }

    eAttitude = AI_getAttitude(eTeam);

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (eAttitude <= GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getDefensivePactRefuseAttitudeThreshold())
                {
                    return DENIAL_ATTITUDE;
                }
            }
        }
    }

    return NO_DENIAL;
}


DenialTypes CvTeamAI::AI_permanentAllianceTrade(TeamTypes eTeam) const
{
    PROFILE_FUNC();

    AttitudeTypes eAttitude;
    int iI;

    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");

    if (isHuman())
    {
        return NO_DENIAL;
    }

    if (AI_getWorstEnemy() == eTeam)
    {
        return DENIAL_WORST_ENEMY;
    }

    if ((getPower(true) + GET_TEAM(eTeam).getPower(true)) > (GC.getGameINLINE().countTotalCivPower() / 2))
    {
        if (getPower(true) > GET_TEAM(eTeam).getPower(true))
        {
            return DENIAL_POWER_US;
        }
        else
        {
            return DENIAL_POWER_YOU;
        }
    }

    if ((AI_getDefensivePactCounter(eTeam) + AI_getShareWarCounter(eTeam)) < 40)
    {
        return DENIAL_NOT_ALLIED;
    }

    eAttitude = AI_getAttitude(eTeam);

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if (eAttitude <= GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getPermanentAllianceRefuseAttitudeThreshold())
                {
                    return DENIAL_ATTITUDE;
                }
            }
        }
    }

    return NO_DENIAL;
}


TeamTypes CvTeamAI::AI_getWorstEnemy() const
{
    return m_eWorstEnemy;
}


void CvTeamAI::AI_updateWorstEnemy()
{
    PROFILE_FUNC();

    TeamTypes eBestTeam = NO_TEAM;
    int iBestValue = MAX_INT;

    for (int iI = 0; iI < MAX_CIV_TEAMS; iI++)
    {
        TeamTypes eLoopTeam = (TeamTypes) iI;
        CvTeam& kLoopTeam = GET_TEAM(eLoopTeam);
        if (kLoopTeam.isAlive())
        {
            if (iI != getID() && !kLoopTeam.isVassal(getID()))
            {
                if (isHasMet(eLoopTeam))
                {
                    if (AI_getAttitude(eLoopTeam) < ATTITUDE_CAUTIOUS)
                    {
                        int iValue = AI_getAttitudeVal(eLoopTeam);
                        if (iValue < iBestValue)
                        {
                            iBestValue = iValue;
                            eBestTeam = eLoopTeam;
                        }
                    }
                }
            }
        }
    }

    m_eWorstEnemy = eBestTeam;
}


int CvTeamAI::AI_getWarPlanStateCounter(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiWarPlanStateCounter[eIndex];
}


void CvTeamAI::AI_setWarPlanStateCounter(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiWarPlanStateCounter[eIndex] = iNewValue;
    FAssert(AI_getWarPlanStateCounter(eIndex) >= 0);
}


void CvTeamAI::AI_changeWarPlanStateCounter(TeamTypes eIndex, int iChange)
{
    AI_setWarPlanStateCounter(eIndex, (AI_getWarPlanStateCounter(eIndex) + iChange));
}


int CvTeamAI::AI_getAtWarCounter(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiAtWarCounter[eIndex];
}


void CvTeamAI::AI_setAtWarCounter(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiAtWarCounter[eIndex] = iNewValue;
    FAssert(AI_getAtWarCounter(eIndex) >= 0);
}


void CvTeamAI::AI_changeAtWarCounter(TeamTypes eIndex, int iChange)
{
    AI_setAtWarCounter(eIndex, (AI_getAtWarCounter(eIndex) + iChange));
}


int CvTeamAI::AI_getAtPeaceCounter(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiAtPeaceCounter[eIndex];
}


void CvTeamAI::AI_setAtPeaceCounter(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiAtPeaceCounter[eIndex] = iNewValue;
    FAssert(AI_getAtPeaceCounter(eIndex) >= 0);
}


void CvTeamAI::AI_changeAtPeaceCounter(TeamTypes eIndex, int iChange)
{
    AI_setAtPeaceCounter(eIndex, (AI_getAtPeaceCounter(eIndex) + iChange));
}


int CvTeamAI::AI_getHasMetCounter(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiHasMetCounter[eIndex];
}


void CvTeamAI::AI_setHasMetCounter(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiHasMetCounter[eIndex] = iNewValue;
    FAssert(AI_getHasMetCounter(eIndex) >= 0);
}


void CvTeamAI::AI_changeHasMetCounter(TeamTypes eIndex, int iChange)
{
    AI_setHasMetCounter(eIndex, (AI_getHasMetCounter(eIndex) + iChange));
}


int CvTeamAI::AI_getOpenBordersCounter(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiOpenBordersCounter[eIndex];
}


void CvTeamAI::AI_setOpenBordersCounter(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiOpenBordersCounter[eIndex] = iNewValue;
    FAssert(AI_getOpenBordersCounter(eIndex) >= 0);
}


void CvTeamAI::AI_changeOpenBordersCounter(TeamTypes eIndex, int iChange)
{
    AI_setOpenBordersCounter(eIndex, (AI_getOpenBordersCounter(eIndex) + iChange));
}


int CvTeamAI::AI_getDefensivePactCounter(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiDefensivePactCounter[eIndex];
}


void CvTeamAI::AI_setDefensivePactCounter(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiDefensivePactCounter[eIndex] = iNewValue;
    FAssert(AI_getDefensivePactCounter(eIndex) >= 0);
}


void CvTeamAI::AI_changeDefensivePactCounter(TeamTypes eIndex, int iChange)
{
    AI_setDefensivePactCounter(eIndex, (AI_getDefensivePactCounter(eIndex) + iChange));
}


int CvTeamAI::AI_getShareWarCounter(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiShareWarCounter[eIndex];
}


void CvTeamAI::AI_setShareWarCounter(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiShareWarCounter[eIndex] = iNewValue;
    FAssert(AI_getShareWarCounter(eIndex) >= 0);
}


void CvTeamAI::AI_changeShareWarCounter(TeamTypes eIndex, int iChange)
{
    AI_setShareWarCounter(eIndex, (AI_getShareWarCounter(eIndex) + iChange));
}


int CvTeamAI::AI_getWarSuccess(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiWarSuccess[eIndex];
}


void CvTeamAI::AI_setWarSuccess(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiWarSuccess[eIndex] = iNewValue;
    FAssert(AI_getWarSuccess(eIndex) >= 0);
}


void CvTeamAI::AI_changeWarSuccess(TeamTypes eIndex, int iChange)
{
    AI_setWarSuccess(eIndex, (AI_getWarSuccess(eIndex) + iChange));
}


int CvTeamAI::AI_getEnemyPeacetimeTradeValue(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiEnemyPeacetimeTradeValue[eIndex];
}


void CvTeamAI::AI_setEnemyPeacetimeTradeValue(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiEnemyPeacetimeTradeValue[eIndex] = iNewValue;
    FAssert(AI_getEnemyPeacetimeTradeValue(eIndex) >= 0);
}


void CvTeamAI::AI_changeEnemyPeacetimeTradeValue(TeamTypes eIndex, int iChange)
{
    AI_setEnemyPeacetimeTradeValue(eIndex, (AI_getEnemyPeacetimeTradeValue(eIndex) + iChange));
}


int CvTeamAI::AI_getEnemyPeacetimeGrantValue(TeamTypes eIndex) const
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    return m_aiEnemyPeacetimeGrantValue[eIndex];
}


void CvTeamAI::AI_setEnemyPeacetimeGrantValue(TeamTypes eIndex, int iNewValue)
{
    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");
    m_aiEnemyPeacetimeGrantValue[eIndex] = iNewValue;
    FAssert(AI_getEnemyPeacetimeGrantValue(eIndex) >= 0);
}


void CvTeamAI::AI_changeEnemyPeacetimeGrantValue(TeamTypes eIndex, int iChange)
{
    AI_setEnemyPeacetimeGrantValue(eIndex, (AI_getEnemyPeacetimeGrantValue(eIndex) + iChange));
}


WarPlanTypes CvTeamAI::AI_getWarPlan(TeamTypes eIndex) const
{
    FAssert(eIndex >= 0);
    FAssert(eIndex < MAX_TEAMS);
    FAssert(eIndex != getID() || m_aeWarPlan[eIndex] == NO_WARPLAN);
    return m_aeWarPlan[eIndex];
}


bool CvTeamAI::AI_isChosenWar(TeamTypes eIndex) const
{
    switch (AI_getWarPlan(eIndex))
    {
    case WARPLAN_ATTACKED_RECENT:
    case WARPLAN_ATTACKED:
        return false;
        break;
    case WARPLAN_PREPARING_LIMITED:
    case WARPLAN_PREPARING_TOTAL:
    case WARPLAN_LIMITED:
    case WARPLAN_TOTAL:
    case WARPLAN_DOGPILE:
        return true;
        break;
    }

    return false;
}


bool CvTeamAI::AI_isSneakAttackPreparing(TeamTypes eIndex) const
{
    return ((AI_getWarPlan(eIndex) == WARPLAN_PREPARING_LIMITED) || (AI_getWarPlan(eIndex) == WARPLAN_PREPARING_TOTAL));
}


bool CvTeamAI::AI_isSneakAttackReady(TeamTypes eIndex) const
{
    return (AI_isChosenWar(eIndex) && !(AI_isSneakAttackPreparing(eIndex)));
}


void CvTeamAI::AI_setWarPlan(TeamTypes eIndex, WarPlanTypes eNewValue, bool bWar)
{
    int iI;

    FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
    FAssertMsg(eIndex < MAX_TEAMS, "eIndex is expected to be within maximum bounds (invalid Index)");

    if (AI_getWarPlan(eIndex) != eNewValue)
    {
        if (bWar || !isAtWar(eIndex))
        {
            m_aeWarPlan[eIndex] = eNewValue;

            AI_setWarPlanStateCounter(eIndex, 0);

            AI_updateAreaStragies();

            for (iI = 0; iI < MAX_PLAYERS; iI++)
            {
                if (GET_PLAYER((PlayerTypes)iI).isAlive())
                {
                    if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
                    {
                        if (!(GET_PLAYER((PlayerTypes)iI).isHuman()))
                        {
                            GET_PLAYER((PlayerTypes)iI).AI_makeProductionDirty();
                        }
                    }
                }
            }
        }
    }
}

//if this number is over 0 the teams are "close"
//this may be expensive to run, kinda O(N^2)...
int CvTeamAI::AI_teamCloseness(TeamTypes eIndex, int iMaxDistance) const
{
    PROFILE_FUNC();
    int iI, iJ;
 
    if (iMaxDistance == -1)
    {
        iMaxDistance = DEFAULT_PLAYER_CLOSENESS;
    }
 
    FAssert(eIndex != getID());
    int iValue = 0;
    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
                {
                    if (GET_PLAYER((PlayerTypes)iJ).isAlive())
                    {
                        if (GET_PLAYER((PlayerTypes)iJ).getTeam() == eIndex)
                        {
                            iValue += GET_PLAYER((PlayerTypes)iI).AI_playerCloseness((PlayerTypes)iJ, iMaxDistance);
                        }
                    }
                }
            }
        }
    }
 
    return iValue;
}


void CvTeamAI::read(FDataStreamBase* pStream)
{
    CvTeam::read(pStream);

    uint uiFlag=0;
    pStream->Read(&uiFlag);    // flags for expansion

    pStream->Read(MAX_TEAMS, m_aiWarPlanStateCounter);
    pStream->Read(MAX_TEAMS, m_aiAtWarCounter);
    pStream->Read(MAX_TEAMS, m_aiAtPeaceCounter);
    pStream->Read(MAX_TEAMS, m_aiHasMetCounter);
    pStream->Read(MAX_TEAMS, m_aiOpenBordersCounter);
    pStream->Read(MAX_TEAMS, m_aiDefensivePactCounter);
    pStream->Read(MAX_TEAMS, m_aiShareWarCounter);
    pStream->Read(MAX_TEAMS, m_aiWarSuccess);
    pStream->Read(MAX_TEAMS, m_aiEnemyPeacetimeTradeValue);
    pStream->Read(MAX_TEAMS, m_aiEnemyPeacetimeGrantValue);

    pStream->Read(MAX_TEAMS, (int*)m_aeWarPlan);
    pStream->Read((int*)&m_eWorstEnemy);
}


void CvTeamAI::write(FDataStreamBase* pStream)
{
    CvTeam::write(pStream);

    uint uiFlag=0;
    pStream->Write(uiFlag);        // flag for expansion

    pStream->Write(MAX_TEAMS, m_aiWarPlanStateCounter);
    pStream->Write(MAX_TEAMS, m_aiAtWarCounter);
    pStream->Write(MAX_TEAMS, m_aiAtPeaceCounter);
    pStream->Write(MAX_TEAMS, m_aiHasMetCounter);
    pStream->Write(MAX_TEAMS, m_aiOpenBordersCounter);
    pStream->Write(MAX_TEAMS, m_aiDefensivePactCounter);
    pStream->Write(MAX_TEAMS, m_aiShareWarCounter);
    pStream->Write(MAX_TEAMS, m_aiWarSuccess);
    pStream->Write(MAX_TEAMS, m_aiEnemyPeacetimeTradeValue);
    pStream->Write(MAX_TEAMS, m_aiEnemyPeacetimeGrantValue);

    pStream->Write(MAX_TEAMS, (int*)m_aeWarPlan);
    pStream->Write(m_eWorstEnemy);
}

// Protected Functions...

int CvTeamAI::AI_noTechTradeThreshold() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getNoTechTradeThreshold();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_techTradeKnownPercent() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getTechTradeKnownPercent();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_maxWarRand() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getMaxWarRand();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_maxWarNearbyPowerRatio() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getMaxWarNearbyPowerRatio();
                iCount++;
            }
        }
    }

    if (iCount > 1)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_maxWarDistantPowerRatio() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getMaxWarDistantPowerRatio();
                iCount++;
            }
        }
    }

    if (iCount > 1)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_maxWarMinAdjacentLandPercent() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getMaxWarMinAdjacentLandPercent();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_limitedWarRand() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getLimitedWarRand();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_limitedWarPowerRatio() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getLimitedWarPowerRatio();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_dogpileWarRand() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getDogpileWarRand();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_makePeaceRand() const
{
    int iRand;
    int iCount;
    int iI;

    iRand = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iRand += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getMakePeaceRand();
                iCount++;
            }
        }
    }

    if (iCount > 0)
    {
        iRand /= iCount;
    }

    return iRand;
}


int CvTeamAI::AI_noWarAttitudeProb(AttitudeTypes eAttitude) const
{
    int iProb;
    int iCount;
    int iI;

    iProb = 0;
    iCount = 0;

    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                iProb += GC.getLeaderHeadInfo(GET_PLAYER((PlayerTypes)iI).getPersonalityType()).getNoWarAttitudeProb(eAttitude);
                iCount++;
            }
        }
    }

    if (iCount > 1)
    {
        iProb /= iCount;
    }

    return iProb;
}


void CvTeamAI::AI_doCounter()
{
    int iI;

    for (iI = 0; iI < MAX_TEAMS; iI++)
    {
        if (GET_TEAM((TeamTypes)iI).isAlive())
        {
            if (iI != getID())
            {
                AI_changeWarPlanStateCounter(((TeamTypes)iI), 1);

                if (isAtWar((TeamTypes)iI))
                {
                    AI_changeAtWarCounter(((TeamTypes)iI), 1);
                }
                else
                {
                    AI_changeAtPeaceCounter(((TeamTypes)iI), 1);
                }

                if (isHasMet((TeamTypes)iI))
                {
                    AI_changeHasMetCounter(((TeamTypes)iI), 1);
                }

                if (isOpenBorders((TeamTypes)iI))
                {
                    AI_changeOpenBordersCounter(((TeamTypes)iI), 1);
                }

                if (isDefensivePact((TeamTypes)iI))
                {
                    AI_changeDefensivePactCounter(((TeamTypes)iI), 1);
                }
                else
                {
                    if (AI_getDefensivePactCounter((TeamTypes)iI) > 0)
                    {
                        AI_changeDefensivePactCounter(((TeamTypes)iI), -1);
                    }
                }

                if (isHasMet((TeamTypes)iI))
                {
                    if (AI_shareWar((TeamTypes)iI))
                    {
                        AI_changeShareWarCounter(((TeamTypes)iI), 1);
                    }
                }
            }
        }
    }
}


void CvTeamAI::AI_doWar()
{
    PROFILE_FUNC();

    CvArea* pLoopArea;
    TeamTypes eBestTeam;
    bool bAreaValid;
    bool bShareValid;
    bool bOffensiveValid;
    int iNoWarRoll;
    int iOurPower;
    int iDogpilePower;
    int iValue;
    int iBestValue;
    int iPass;
    int iLoop;
    int iI, iJ;

    FAssert(!isHuman());
    FAssert(!isBarbarian());
    FAssert(!isMinorCiv());

    if (isAVassal())
    {
        return;
    }

    // allow python to handle it
    CyArgsList argsList;
    argsList.add(getID());
    long lResult=0;
    gDLL->getPythonIFace()->callFunction(PYGameModule, "AI_doWar", argsList.makeFunctionArgs(), &lResult);
    if (lResult == 1)
    {
        return;
    }

    for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
    {
        if (GET_TEAM((TeamTypes)iI).isAlive())
        {
            if (AI_getWarPlan((TeamTypes)iI) != NO_WARPLAN)
            {
                int iTimeModifier = 100;
                {
                    int iOurPower = getPower(true);
                    int iTheirPower = GET_TEAM((TeamTypes)iI).getPower(true);
               
                    int iRatio = (1 + iOurPower) / (1 + iTheirPower);
               
                    if (iRatio > 200)
                    {
                        iTimeModifier *= 100;
                        iTimeModifier /= iRatio - 100;
                    }
               
                    iTimeModifier *= 50 + GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getTrainPercent();
                    iTimeModifier /= 150;
                    FAssert(iTimeModifier > 0);
                }
               
                if (AI_getWarPlan((TeamTypes)iI) == WARPLAN_ATTACKED_RECENT)
                {
                    FAssert(isAtWar((TeamTypes)iI));

                    if (AI_getAtWarCounter((TeamTypes)iI) > ((GET_TEAM((TeamTypes)iI).AI_isLandTarget(getID())) ? 9 : 3))
                    {
                        AI_setWarPlan(((TeamTypes)iI), WARPLAN_ATTACKED);
                    }
                }
                else if (AI_getWarPlan((TeamTypes)iI) == WARPLAN_PREPARING_LIMITED)
                {
                    FAssert(canDeclareWar((TeamTypes)iI));

                    if (AI_getWarPlanStateCounter((TeamTypes)iI) > ((5 * iTimeModifier) / 100))
                    {
                        AI_setWarPlan(((TeamTypes)iI), WARPLAN_LIMITED);
                    }
                }
                else if (AI_getWarPlan((TeamTypes)iI) == WARPLAN_PREPARING_TOTAL)
                {
                    FAssert(canDeclareWar((TeamTypes)iI));

                    if (AI_getWarPlanStateCounter((TeamTypes)iI) > ((10 * iTimeModifier) / 100))
                    {
                        bAreaValid = true;
                        bShareValid = false;

                        for(pLoopArea = GC.getMapINLINE().firstArea(&iLoop); pLoopArea != NULL; pLoopArea = GC.getMapINLINE().nextArea(&iLoop))
                        {
                            if (AI_isPrimaryArea(pLoopArea))
                            {
                                if (GET_TEAM((TeamTypes)iI).countNumCitiesByArea(pLoopArea) > 0)
                                {
                                    bShareValid = true;

                                    bOffensiveValid = false;

                                    if (AI_calculateAreaAIType(pLoopArea, true) == AREAAI_OFFENSIVE)
                                    {
                                        bOffensiveValid = true;
                                    }

                                    if (!bOffensiveValid)
                                    {
                                        bAreaValid = false;
                                    }
                                }
                            }
                        }

                        if (bAreaValid || !bShareValid)
                        {
                            AI_setWarPlan(((TeamTypes)iI), WARPLAN_TOTAL);
                        }
                        else if (AI_getWarPlanStateCounter((TeamTypes)iI) > ((20 * iTimeModifier) / 100))
                        {
                            AI_setWarPlan(((TeamTypes)iI), NO_WARPLAN);
                        }
                    }
                }
            }
        }
    }

    for (iI = 0; iI < MAX_CIV_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                GET_PLAYER((PlayerTypes)iI).AI_doPeace();
            }
        }
    }
 
    int iNumMembers = getNumMembers();
    int iHighUnitSpendingPercent = 0;
    int iLowUnitSpendingPercent = 0;
 
    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                int iUnitSpendingPercent = (GET_PLAYER((PlayerTypes)iI).calculateUnitCost() * 100) / std::max(1, GET_PLAYER((PlayerTypes)iI).calculatePreInflatedCosts());
                iHighUnitSpendingPercent += (std::max(0, iUnitSpendingPercent - 7) / 2);
                iLowUnitSpendingPercent += iUnitSpendingPercent;
            }        
        }
    }
 
    iHighUnitSpendingPercent /= iNumMembers;
    iLowUnitSpendingPercent /= iNumMembers;
 
    // if at war, check for making peace
    if (getAtWarCount(true) > 0) // XXX
    {
        if (GC.getGameINLINE().getSorenRandNum(AI_makePeaceRand(), "AI Make Peace") == 0)
        {
            for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
            {
                if (GET_TEAM((TeamTypes)iI).isAlive())
                {
                    if (iI != getID())
                    {
                        if (!(GET_TEAM((TeamTypes)iI).isHuman()))
                        {
                            if (canContact((TeamTypes)iI))
                            {
                                FAssert(!(GET_TEAM((TeamTypes)iI).isMinorCiv()));

                                if (isAtWar((TeamTypes)iI))
                                {
                                    if (AI_isChosenWar((TeamTypes)iI))
                                    {
                                        if (AI_getAtWarCounter((TeamTypes)iI) > 20)
                                        {
                                            // removed this, it prevents conquest and domination victories
                                            // have to make sure diplomacy begs for mercy properly in AI-AI relations
                                            //if (AI_getAtWarCounter((TeamTypes)iI) > 50)
                                            //{
                                            //    makePeace((TeamTypes)iI);
                                            //    break;
                                            //}

                                            if (AI_getAtWarCounter((TeamTypes)iI) > ((AI_getWarPlan((TeamTypes)iI) == WARPLAN_TOTAL) ? 40 : 30))
                                            {
                                                int iOurValue = AI_endWarVal((TeamTypes)iI);
                                                int iTheirValue = GET_TEAM((TeamTypes)iI).AI_endWarVal(getID());
                                                if ((iOurValue > (iTheirValue / 2)) && (iTheirValue > (iOurValue / 2)))
                                                {
                                                    makePeace((TeamTypes)iI);
                                                    break;
                                                }
                                            }

                                            if (AI_getWarPlan((TeamTypes)iI) == WARPLAN_DOGPILE)
                                            {
                                                if (GET_TEAM((TeamTypes)iI).getAtWarCount(true) == 1)
                                                {
                                                    makePeace((TeamTypes)iI);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    // if no war plans, consider starting one!
    else if (getAnyWarPlanCount(true) == 0)
    {
        bool bAggressive = GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI);
   
        int iFinancialTroubleCount = 0;
        int iDaggerCount = 0;
        int iGetBetterUnitsCount = 0;
        bool bFinalWar = false;
        for (iI = 0; iI < MAX_PLAYERS; iI++)
        {
            if (GET_PLAYER((PlayerTypes)iI).isAlive())
            {
                if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
                {
                    if (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_DAGGER))
                    {
                        iDaggerCount++;
                        bAggressive = true;
                    }
                    if (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_GET_BETTER_UNITS))
                    {
                        iGetBetterUnitsCount++;
                    }
               
                    if (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_FINAL_WAR))
                    {
                        bFinalWar = true;
                    }
               
                    if (GET_PLAYER((PlayerTypes)iI).AI_isFinancialTrouble())
                    {
                        iFinancialTroubleCount++;
                    }
                }
            }
        }

        // if random in this range is 0, we go to war of this type (so lower numbers are higher probablity)
        // average of everyone on our team
        int iMaxWarRand = AI_maxWarRand();
        int iLimitedWarRand = AI_limitedWarRand();
        int iDogpileWarRand = AI_dogpileWarRand();
   
        int iNumVassals = getVassalCount();
   
        iMaxWarRand *= iNumMembers;
        iMaxWarRand /= (iNumMembers + iNumVassals);
   
        if (bFinalWar)
        {
            iMaxWarRand /= 4;
        }

        iLimitedWarRand *= iNumMembers;
        iLimitedWarRand /= (iNumMembers + iNumVassals);
   
        iDogpileWarRand *= iNumMembers;
        iDogpileWarRand /= (iNumMembers + iNumVassals);
   
        int iWarRandThreshold = iHighUnitSpendingPercent * (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 4 : 2);
        iWarRandThreshold /= 3;
        iWarRandThreshold += GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 1 : 0;
   
        // we oppose war if half the non-dagger teammates in financial trouble
        bool bFinancesOpposeWar = false;
        if ((iFinancialTroubleCount - iDaggerCount) >= std::max(1, getNumMembers() / 2 ))
        {
            // this can be overridden by by the pro-war booleans
            bFinancesOpposeWar = true;
        }

        // if agressive, we may start a war to get money
        bool bFinancesProMaxWar = false;
        bool bFinancesProLimitedWar = false;
        bool bFinancesProDogpileWar = false;
        if (iFinancialTroubleCount > 0)
        {
            // do we like all out wars?
            if (iDaggerCount > 0 || iMaxWarRand < 100)
            {
                bFinancesProMaxWar = true;
            }

            // do we like limited wars?
            if (iLimitedWarRand < 100)
            {
                bFinancesProLimitedWar = true;
            }
       
            // do we like dogpile wars?
            if (iDogpileWarRand < 100)
            {
                bFinancesProDogpileWar = true;
            }
        }
        bool bFinancialProWar = (bFinancesProMaxWar || bFinancesProLimitedWar || bFinancesProDogpileWar);
   
        // overall war check (quite frequently true)
        bool bMakeWarChecks = false;
        if (iGetBetterUnitsCount * 3 < iNumMembers * 2)
        {
            if (bFinancialProWar || !bFinancesOpposeWar)
            {
                // random overall war chance (at noble+ difficulties this is 100%)
                if (GC.getGameINLINE().getSorenRandNum(100, "AI Declare War 1") < GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIDeclareWarProb())
                {
                    // if non-agressive, random based on number of cities (the more cities, the less war)
                    if ((bAggressive || bFinancialProWar) ? true : (GC.getGameINLINE().getSorenRandNum(4, "AI Declare War 2") != 0))
                    {
                        bMakeWarChecks = true;
                    }
                }
            }
        }
   
        if (bMakeWarChecks)
        {
            iOurPower = getPower(true);

            if (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI))
            {
                iOurPower *= 4;
                iOurPower /= 3;
            }

            if ((bFinancesProMaxWar || !bFinancesOpposeWar) &&
                (GC.getGameINLINE().getSorenRandNum(iMaxWarRand, "AI Maximum War") <= iWarRandThreshold))
            {
                iNoWarRoll = GC.getGameINLINE().getSorenRandNum(100, "AI No War") - 0;
                iNoWarRoll = range(iNoWarRoll + (bAggressive ? 10 : 0) + (bFinancesProMaxWar ? 10 : 0), 0, 99);

                iBestValue = 0;
                eBestTeam = NO_TEAM;

                for (iPass = 0; iPass < 3; iPass++)
                {
                    for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
                    {
                        if (GET_TEAM((TeamTypes)iI).isAlive())
                        {
                            if (iI != getID())
                            {
                                if (isHasMet((TeamTypes)iI))
                                {
                                    if (canDeclareWar((TeamTypes)iI))
                                    {
                                        if (iNoWarRoll >= AI_noWarAttitudeProb(AI_getAttitude((TeamTypes)iI)))
                                        {
                                            int iDefensivePower = (GET_TEAM((TeamTypes)iI).getDefensivePower() * 2) / 3;
                                       
                                            if (iDefensivePower < ((iOurPower * ((iPass > 1) ? AI_maxWarDistantPowerRatio() : AI_maxWarNearbyPowerRatio())) / 100))
                                            {
                                                // XXX make sure they share an area....

                                                FAssertMsg(!(GET_TEAM((TeamTypes)iI).isBarbarian()), "Expected to not be declaring war on the barb civ");
                                                FAssertMsg(iI != getID(), "Expected not to be declaring war on self (DOH!)");

                                                if ((iPass > 1) || (AI_isLandTarget((TeamTypes)iI) || AI_isAnyCapitalAreaAlone()))
                                                {
                                                    if ((iPass > 0) || (AI_calculateAdjacentLandPlots((TeamTypes)iI) >= ((getTotalLand() * AI_maxWarMinAdjacentLandPercent()) / 100)))
                                                    {
                                                        iValue = AI_startWarVal((TeamTypes)iI);

                                                        if (iValue > iBestValue)
                                                        {
                                                            iBestValue = iValue;
                                                            eBestTeam = ((TeamTypes)iI);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if (eBestTeam != NO_TEAM)
                    {
                        AI_setWarPlan(eBestTeam, (iDaggerCount > 0) ? WARPLAN_TOTAL : WARPLAN_PREPARING_TOTAL);
                        break;
                    }
                }
            }
            else if ((bFinancesProMaxWar || !bFinancesOpposeWar) &&
                (GC.getGameINLINE().getSorenRandNum(iLimitedWarRand, "AI Limited War") == 0))
            {
                iNoWarRoll = GC.getGameINLINE().getSorenRandNum(100, "AI No War") - 10;
                iNoWarRoll = range(iNoWarRoll + (bAggressive ? 10 : 0) + (bFinancesProLimitedWar ? 10 : 0), 0, 99);

                iBestValue = 0;
                eBestTeam = NO_TEAM;

                for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
                {
                    if (GET_TEAM((TeamTypes)iI).isAlive())
                    {
                        if (iI != getID())
                        {
                            if (isHasMet((TeamTypes)iI))
                            {
                                if (canDeclareWar((TeamTypes)iI))
                                {
                                    if (iNoWarRoll >= AI_noWarAttitudeProb(AI_getAttitude((TeamTypes)iI)))
                                    {
                                        if (AI_isLandTarget((TeamTypes)iI) || (AI_isAnyCapitalAreaAlone() && GET_TEAM((TeamTypes)iI).AI_isAnyCapitalAreaAlone()))
                                        {
                                            if (GET_TEAM((TeamTypes)iI).getDefensivePower() < ((iOurPower * AI_limitedWarPowerRatio()) / 100))
                                            {
                                                iValue = AI_startWarVal((TeamTypes)iI);

                                                if (iValue > iBestValue)
                                                {
                                                    FAssert(!AI_shareWar((TeamTypes)iI));
                                                    iBestValue = iValue;
                                                    eBestTeam = ((TeamTypes)iI);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if (eBestTeam != NO_TEAM)
                {
                    AI_setWarPlan(eBestTeam, (iDaggerCount > 0) ? WARPLAN_LIMITED : WARPLAN_PREPARING_LIMITED);
                }
            }
            else if ((bFinancesProDogpileWar || !bFinancesOpposeWar) &&
                (GC.getGameINLINE().getSorenRandNum(iDogpileWarRand, "AI Dogpile War") == 0))
            {
                iNoWarRoll = GC.getGameINLINE().getSorenRandNum(100, "AI No War") - 20;
                iNoWarRoll = range(iNoWarRoll + (bAggressive ? 10 : 0) + (bFinancesProDogpileWar ? 10 : 0), 0, 99);

                iBestValue = 0;
                eBestTeam = NO_TEAM;

                for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
                {
                    if (GET_TEAM((TeamTypes)iI).isAlive())
                    {
                        if (iI != getID())
                        {
                            if (isHasMet((TeamTypes)iI))
                            {
                                if (canDeclareWar((TeamTypes)iI))
                                {
                                    if (iNoWarRoll >= AI_noWarAttitudeProb(AI_getAttitude((TeamTypes)iI)))
                                    {
                                        if (GET_TEAM((TeamTypes)iI).getAtWarCount(true) > 0)
                                        {
                                            if (AI_isLandTarget((TeamTypes)iI))
                                            {
                                                iDogpilePower = iOurPower;

                                                for (iJ = 0; iJ < MAX_CIV_TEAMS; iJ++)
                                                {
                                                    if (GET_TEAM((TeamTypes)iJ).isAlive())
                                                    {
                                                        if (iJ != iI)
                                                        {
                                                            if (atWar(((TeamTypes)iJ), ((TeamTypes)iI)))
                                                            {
                                                                iDogpilePower += GET_TEAM((TeamTypes)iJ).getPower(false);
                                                            }
                                                        }
                                                    }
                                                }

                                                FAssert(GET_TEAM((TeamTypes)iI).getPower(true) == GET_TEAM((TeamTypes)iI).getDefensivePower() || GET_TEAM((TeamTypes)iI).isAVassal());

                                                if (((GET_TEAM((TeamTypes)iI).getDefensivePower() * 3) / 2) < iDogpilePower)
                                                {
                                                    iValue = AI_startWarVal((TeamTypes)iI);

                                                    if (iValue > iBestValue)
                                                    {
                                                        FAssert(!AI_shareWar((TeamTypes)iI));
                                                        iBestValue = iValue;
                                                        eBestTeam = ((TeamTypes)iI);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if (eBestTeam != NO_TEAM)
                {
                    AI_setWarPlan(eBestTeam, WARPLAN_DOGPILE);
                }
            }
        }
    }
}

//returns true if war is veto'd by rolls.
bool CvTeamAI::AI_performNoWarRolls(TeamTypes eTeam)
{
 
    if (GC.getGameINLINE().getSorenRandNum(100, "AI Declare War 1") > GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIDeclareWarProb())
    {
        return true;
    }
 
    if (GC.getGameINLINE().getSorenRandNum(100, "AI No War") <= AI_noWarAttitudeProb(AI_getAttitude(eTeam)))
    {
        return true;    
    }
 
 
 
    return false;
}

int CvTeamAI::AI_getAttitudeWeight(TeamTypes eTeam)
{
    int iAttitudeWeight = 0;
    switch (AI_getAttitude(eTeam))
    {
    case ATTITUDE_FURIOUS:
        iAttitudeWeight = -100;
        break;
    case ATTITUDE_ANNOYED:
        iAttitudeWeight = -40;
        break;
    case ATTITUDE_CAUTIOUS:
        iAttitudeWeight = -5;
        break;
    case ATTITUDE_PLEASED:
        iAttitudeWeight = 50;
        break;
    case ATTITUDE_FRIENDLY:
        iAttitudeWeight = 100;        
        break;
    }
 
    return iAttitudeWeight;
}

int CvTeamAI::AI_getLowestVictoryCountdown() const
{
    int iBestVictoryCountdown = MAX_INT;
    for (int iVictory = 0; iVictory < GC.getNumVictoryInfos(); iVictory++)
    {
         int iCountdown = getVictoryCountdown((VictoryTypes)iVictory);
         if (iCountdown > 0)
         {
            iBestVictoryCountdown = std::min(iBestVictoryCountdown, iCountdown);
         }
    }
    if (MAX_INT == iBestVictoryCountdown)
    {
        iBestVictoryCountdown = -1;
    }
    return iBestVictoryCountdown;
}

int CvTeamAI::AI_getTechMonopolyValue(TechTypes eTech, TeamTypes eTeam) const
{
    int iValue = 0;
    int iI;
 
    bool bWarPlan = (getAnyWarPlanCount(eTeam) > 0);
 
    for (iI = 0; iI < GC.getNumUnitClassInfos(); iI++)
    {
        UnitTypes eLoopUnit = ((UnitTypes)GC.getUnitClassInfo((UnitClassTypes)iI).getDefaultUnitIndex());

        if (eLoopUnit != NO_UNIT)
        {
            if (isTechRequiredForUnit((eTech), eLoopUnit))
            {
                if (isWorldUnitClass((UnitClassTypes)iI))
                {
                    iValue += 50;
                }
           
                if (GC.getUnitInfo(eLoopUnit).getPrereqAndTech() == eTech)
                {
                    int iNavalValue = 0;
               
                    int iCombatRatio = (GC.getUnitInfo(eLoopUnit).getCombat() * 100) / std::max(1, GC.getGameINLINE().getBestLandUnitCombat());
                    if (iCombatRatio > 50)
                    {
                        iValue += ((bWarPlan ? 100 : 50) * (iCombatRatio - 40)) / 50;;
                    }

                    switch (GC.getUnitInfo(eLoopUnit).getDefaultUnitAIType())
                    {
                    case UNITAI_UNKNOWN:
                    case UNITAI_ANIMAL:
                    case UNITAI_SETTLE:
                    case UNITAI_WORKER:
                    break;

                    case UNITAI_ATTACK:
                    case UNITAI_ATTACK_CITY:
                    case UNITAI_COLLATERAL:
                        iValue += bWarPlan ? 50 : 20;
                        break;

                    case UNITAI_PILLAGE:
                    case UNITAI_RESERVE:
                    case UNITAI_COUNTER:
                    case UNITAI_PARADROP:
                    case UNITAI_CITY_DEFENSE:
                    case UNITAI_CITY_COUNTER:
                    case UNITAI_CITY_SPECIAL:
                        iValue += bWarPlan ? 40 : 15;
                        break;


                    case UNITAI_EXPLORE:
                    case UNITAI_MISSIONARY:
                        break;

                    case UNITAI_PROPHET:
                    case UNITAI_ARTIST:
                    case UNITAI_SCIENTIST:
                    case UNITAI_GENERAL:
                    case UNITAI_MERCHANT:
                    case UNITAI_ENGINEER:
                        break;

                    case UNITAI_SPY:
                        break;

                    case UNITAI_ICBM:
                        iValue += bWarPlan ? 80 : 40;
                        break;

                    case UNITAI_WORKER_SEA:
                        break;

                    case UNITAI_ATTACK_SEA:
                        iNavalValue += 50;
                        break;

                    case UNITAI_RESERVE_SEA:
                    case UNITAI_ESCORT_SEA:
                        iNavalValue += 30;
                        break;

                    case UNITAI_EXPLORE_SEA:
                        iValue += GC.getGame().circumnavigationAvailable() ? 100 : 0;
                        break;

                    case UNITAI_ASSAULT_SEA:
                        iNavalValue += 60;
                        break;

                    case UNITAI_SETTLER_SEA:
                    case UNITAI_MISSIONARY_SEA:
                    case UNITAI_SPY_SEA:
                        break;

                    case UNITAI_CARRIER_SEA:
                    case UNITAI_MISSILE_CARRIER_SEA:
                        iNavalValue += 40;
                        break;

                    case UNITAI_PIRATE_SEA:
                        iNavalValue += 20;
                        break;

                    case UNITAI_ATTACK_AIR:
                    case UNITAI_DEFENSE_AIR:
                        iValue += bWarPlan ? 60 : 30;
                        break;

                    case UNITAI_CARRIER_AIR:
                        iNavalValue += 40;
                        break;

                    case UNITAI_MISSILE_AIR:
                        iValue += bWarPlan ? 40 : 20;
                        break;

                    default:
                        FAssert(false);
                        break;
                    }
               
                    if (iNavalValue > 0)
                    {
                        if (AI_isAnyCapitalAreaAlone())
                        {
                            iValue += iNavalValue / 2;
                        }
                        if (bWarPlan && !AI_isLandTarget(eTeam))
                        {
                            iValue += iNavalValue / 2;
                        }
                    }
                }
            }
        }
    }

    for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
    {
        if (isTechRequiredForBuilding(eTech, ((BuildingTypes)iI)))
        {
            CvBuildingInfo& kLoopBuilding = GC.getBuildingInfo((BuildingTypes)iI);
            if (kLoopBuilding.getReligionType() == NO_RELIGION)
            {
                iValue += 30;
            }
            if (isWorldWonderClass((BuildingClassTypes)kLoopBuilding.getBuildingClassType()))
            {
                if (!(GC.getGameINLINE().isBuildingClassMaxedOut((BuildingClassTypes)kLoopBuilding.getBuildingClassType())))
                {
                    iValue += 50;
                }
            }
        }
    }

    for (iI = 0; iI < GC.getNumProjectInfos(); iI++)
    {
        if (GC.getProjectInfo((ProjectTypes)iI).getTechPrereq() == eTech)
        {
            if (isWorldProject((ProjectTypes)iI))
            {
                if (!(GC.getGameINLINE().isProjectMaxedOut((ProjectTypes)iI)))
                {
                    iValue += 100;
                }
            }
            else
            {
                iValue += 50;
            }
        }
    }
 
    return iValue;
 
 
}

bool CvTeamAI::AI_isWaterAreaRelevant(CvArea* pArea)
{
    int iTeamCities = 0;
    int iOtherTeamCities = 0;
 
    if (GC.getMap().findBiggestArea(true) == pArea)
    {
        return true;
    }
 
    //An area is deemed relevant if it has at least 2 cities of our and different teams.
 
    for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; iPlayer++)
    {
        CvPlayerAI& kPlayer = GET_PLAYER((PlayerTypes)iPlayer);
   
        if ((iTeamCities < 2 && (kPlayer.getTeam() == getID())) || (iOtherTeamCities < 2 && (kPlayer.getTeam() != getID())))
        {
            int iLoop;
            CvCity* pLoopCity;
       
            for (pLoopCity = kPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kPlayer.nextCity(&iLoop))
            {
                if (pLoopCity->plot()->isAdjacentToArea(pArea->getID()))
                {
                    if (kPlayer.getTeam() == getID())
                    {
                        iTeamCities++;
                        if (iTeamCities >= 2)
                        {
                            break;
                        }
                    }
                    else
                    {
                        iOtherTeamCities++;
                        if (iOtherTeamCities >= 2)
                        {
                            break;
                        }
                    }
                }            
            }
        }
        if (iTeamCities >= 2 && iOtherTeamCities >= 2)
        {
            return true;
        }
    }
    return false;
}

// Private Functions...
 
Last edited:
I can't really read code, so I can only hope to organize things for easier reading so a code-diver can look it over and comment some day. :please:

Starting from DanF's ancient post:



I think the juiciness calculation in Beyond the Sword 3.19 is this part.

Code:
int CvTeamAI::AI_startWarVal(TeamTypes eTeam) const
{
    PROFILE_FUNC();


    int iValue;


    iValue = AI_calculatePlotWarValue(eTeam);


    iValue += (3 * AI_calculateCapitalProximity(eTeam)) / ((iValue > 0) ? 2 : 3);
 
    int iClosenessValue = AI_teamCloseness(eTeam);
    if (iClosenessValue == 0)
    {
        iValue /= (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 4 : 2);
    }
    iValue += iClosenessValue;
 
    int iOurVictoryCountdown = AI_getLowestVictoryCountdown();
    int iTheirVictoryCountdown = GET_TEAM(eTeam).AI_getLowestVictoryCountdown();
 
    if ((iTheirVictoryCountdown != -1) && ((iOurVictoryCountdown == -1) || iTheirVictoryCountdown < iOurVictoryCountdown))
    {
        iValue ++;
        iValue *= 8;
    }


    //Domination...
    int iOurLandPercent = getTotalLand(true) * 100 / GC.getMapINLINE().getLandPlots();
    int iPercentOfDomination = 0;
    for (int iI = 0; iI < GC.getNumVictoryInfos(); iI++)
    {
        if (GC.getVictoryInfo((VictoryTypes)iI).getLandPercent() > 0)
        {
            iPercentOfDomination = 100 * iOurLandPercent / std::max(1, GC.getGameINLINE().getAdjustedLandPercent((VictoryTypes)iI));
        }
    }
 
    if (iPercentOfDomination > 75)
    {
        iValue *= (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 6 : 4);
    }


    switch (AI_getAttitude(eTeam))
    {
    case ATTITUDE_FURIOUS:
        iValue *= 16;
        break;


    case ATTITUDE_ANNOYED:
        iValue *= 8;
        break;


    case ATTITUDE_CAUTIOUS:
        iValue *= 4;
        break;


    case ATTITUDE_PLEASED:
        iValue *= 2;
        break;


    case ATTITUDE_FRIENDLY:
        iValue *= 1;
        break;


    default:
        FAssert(false);
        break;
    }
 
    int iMaxCultureVictoryAdjustment = 1;
    for (int iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if  (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if  (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_CULTURE3))
                {
                    iMaxCultureVictoryAdjustment = std::max(iMaxCultureVictoryAdjustment, 8);
                }
                else if  (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_CULTURE2))
                {
                    iMaxCultureVictoryAdjustment = std::max(iMaxCultureVictoryAdjustment, 3);
                }
            }
        }
    }
    iValue /= iMaxCultureVictoryAdjustment;


    return iValue;
}

Starting from E1, iValue or the running total of juiciness to pick a war target starts with +4 points for every victim's land tile that the warmonger touches to start?
Is the +40 points per resource still bugged?

Code:
iValue = AI_calculatePlotWarValue(eTeam);
It requires AI_calculatePlotWarValue to be calculated.
Spoiler :

Code:
int CvTeamAI::AI_calculatePlotWarValue(TeamTypes eTeam) const
{
    FAssert(eTeam != getID());


    int iValue = 0;


    for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
    {
        CvPlot* pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);


        if (pLoopPlot->getTeam() == eTeam)
        {
            if (!pLoopPlot->isWater() && pLoopPlot->isAdjacentTeam(getID(), true))
            {
                iValue += 4;
            }


            BonusTypes eBonus = pLoopPlot->getBonusType(getID());
            if (NO_BONUS != eBonus)
            {
                iValue += 40 * GC.getBonusInfo(eBonus).getAIObjective();
            }
        }
    }


    return iValue;
}

Hmm, I can't really read code.
Maybe the +40 points from important resources in the victim's lands got fixed in patch 3.19? :hmm:

Next part is E2 and a point addition based on how close the victim's capital is to the warmonger.

Code:
iValue += (3 * AI_calculateCapitalProximity(eTeam)) / ((iValue > 0) ? 2 : 3);
It requires AI_calculateCapitalProximity to be calculated.
We multiply it by 3.
The we divide by 2 if iValue is > 0 is true from our calculation in E1.
Or we divide by 3 if iValue is > 0 is false from our calculation in E1.
Finally, we add the result to iValue and continue to E3.
Spoiler :

Code:
int CvTeamAI::AI_calculateCapitalProximity(TeamTypes eTeam) const
{
    CvCity* pOurCapitalCity;
    CvCity* pTheirCapitalCity;
    int iTotalDistance;
    int iCount;
    int iI, iJ;


    FAssertMsg(eTeam != getID(), "shouldn't call this function on ourselves");


    iTotalDistance = 0;
    iCount = 0;
 
    int iMinDistance = MAX_INT;
    int iMaxDistance = 0;


    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                pOurCapitalCity = GET_PLAYER((PlayerTypes)iI).getCapitalCity();


                if (pOurCapitalCity != NULL)
                {
                    for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
                    {
                        if (GET_PLAYER((PlayerTypes)iJ).isAlive())
                        {
                            if (GET_PLAYER((PlayerTypes)iJ).getTeam() != getID())
                            {
                                pTheirCapitalCity = GET_PLAYER((PlayerTypes)iJ).getCapitalCity();


                                if (pTheirCapitalCity != NULL)
                                {
                                    int iDistance = (plotDistance(pOurCapitalCity->getX_INLINE(), pOurCapitalCity->getY_INLINE(), pTheirCapitalCity->getX_INLINE(), pTheirCapitalCity->getY_INLINE()) * (pOurCapitalCity->area() != pTheirCapitalCity->area() ? 3 : 2));
                                    if (GET_PLAYER((PlayerTypes)iJ).getTeam() == eTeam)
                                    {
                                        iTotalDistance += iDistance;
                                        iCount++;
                                    }
                                    iMinDistance = std::min(iDistance, iMinDistance);
                                    iMaxDistance = std::max(iDistance, iMaxDistance);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
 
    if (iCount > 0)
    {
        FAssert(iMaxDistance > 0);
        return ((GC.getMapINLINE().maxPlotDistance() * (iMaxDistance - ((iTotalDistance / iCount) - iMinDistance))) / iMaxDistance);
    }


    return 0;
}

Ugh, I can't make heads or tails of it.
Whatever AI_calculateCapitalProximity calculates out to be, it seems this point total is multiplied by 1.5 if the victim has a land tile touched by the warmonger.


Next is E3 and closeness of the victim to the warmonger.
Is it still bugged with victim cities' being close to each other that awards points to adjust iValue?

Code:
int iClosenessValue = AI_teamCloseness(eTeam);
    if (iClosenessValue == 0)
    {
        iValue /= (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 4 : 2);
    }
    iValue += iClosenessValue;

It requires AI_teamCloseness to be calculated.
Spoiler :

Code:
//if this number is over 0 the teams are "close"
//this may be expensive to run, kinda O(N^2)...
int CvTeamAI::AI_teamCloseness(TeamTypes eIndex, int iMaxDistance) const
{
    PROFILE_FUNC();
    int iI, iJ;
 
    if (iMaxDistance == -1)
    {
        iMaxDistance = DEFAULT_PLAYER_CLOSENESS;
    }
 
    FAssert(eIndex != getID());
    int iValue = 0;
    for (iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
                {
                    if (GET_PLAYER((PlayerTypes)iJ).isAlive())
                    {
                        if (GET_PLAYER((PlayerTypes)iJ).getTeam() == eIndex)
                        {
                            iValue += GET_PLAYER((PlayerTypes)iI).AI_playerCloseness((PlayerTypes)iJ, iMaxDistance);
                        }
                    }
                }
            }
        }
    }
 
    return iValue;
}

Can't make heads or tails of it. :lol:
iValue continues to be adjusted as we go down the list!

E4
Code:
int iOurVictoryCountdown = AI_getLowestVictoryCountdown();
    int iTheirVictoryCountdown = GET_TEAM(eTeam).AI_getLowestVictoryCountdown();
 
    if ((iTheirVictoryCountdown != -1) && ((iOurVictoryCountdown == -1) || iTheirVictoryCountdown < iOurVictoryCountdown))
    {
        iValue ++;
        iValue *= 8;
    }

E5
Code:
//Domination...
    int iOurLandPercent = getTotalLand(true) * 100 / GC.getMapINLINE().getLandPlots();
    int iPercentOfDomination = 0;
    for (int iI = 0; iI < GC.getNumVictoryInfos(); iI++)
    {
        if (GC.getVictoryInfo((VictoryTypes)iI).getLandPercent() > 0)
        {
            iPercentOfDomination = 100 * iOurLandPercent / std::max(1, GC.getGameINLINE().getAdjustedLandPercent((VictoryTypes)iI));
        }
    }
 
    if (iPercentOfDomination > 75)
    {
        iValue *= (GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 6 : 4);
    }
E6
Code:
switch (AI_getAttitude(eTeam))
    {
    case ATTITUDE_FURIOUS:
        iValue *= 16;
        break;


    case ATTITUDE_ANNOYED:
        iValue *= 8;
        break;


    case ATTITUDE_CAUTIOUS:
        iValue *= 4;
        break;


    case ATTITUDE_PLEASED:
        iValue *= 2;
        break;


    case ATTITUDE_FRIENDLY:
        iValue *= 1;
        break;


    default:
        FAssert(false);
        break;
    }
E7
Code:
int iMaxCultureVictoryAdjustment = 1;
    for (int iI = 0; iI < MAX_PLAYERS; iI++)
    {
        if (GET_PLAYER((PlayerTypes)iI).isAlive())
        {
            if  (GET_PLAYER((PlayerTypes)iI).getTeam() == getID())
            {
                if  (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_CULTURE3))
                {
                    iMaxCultureVictoryAdjustment = std::max(iMaxCultureVictoryAdjustment, 8);
                }
                else if  (GET_PLAYER((PlayerTypes)iI).AI_isDoStrategy(AI_STRATEGY_CULTURE2))
                {
                    iMaxCultureVictoryAdjustment = std::max(iMaxCultureVictoryAdjustment, 3);
                }
            }
        }
    }
    iValue /= iMaxCultureVictoryAdjustment;


    return iValue;
And there we go.
Whichever victim gets the biggest iValue number after being selected as a valid war target, the warmonger picks them to attack.
E4, E5, and E7 only seem to matter at the end of the game.

E6 and the entire total of iValue being multiplied by x4 for Cautious, x8 for Annoyed, and x16 for Furious is huge!


Zooming back out again to part D of DanF's guide, it seems being a Land Target is a huge deal for getting to the front of the line for being a victim to a warmonger?

They just need to touch 8 of your land tiles with their land tiles and you become a Land Target for them unless DanF means something else? :hmm:
An AI rolling for Total War can only attack non-Land Targets on pass 3 if no valid victim was found in pass 1 or pass 2?
An AI can't roll for Limited War if their victim is not a Land Target or the warmonger and victim are both Lonely Hearts (isolated on their own continent/island)?
An AI can't roll for Dogpile War if their victim is not a Land Target or are not at war with another civ?

IMHO by settling eastwards beyond the isthmus you will only do yourself a disservice, since this will make you a valid land target for Nappy. If you can avoid this (< 8 land tiles adjacent to his territory) you are safe from limited wars (Nappy's favourite war, rand 40 vs. 100 for total war) plus you can decrease or even most likely completely avoid close border tensions. An isthmus is also much easier to defend. So I recommend settling your western half and aiming for the great torch, Deity = big AI cities = big trade income!
Good luck!

Take Montezuma.
iMaxWarRand = 50, so has a 2% chance each turn to get the appetite from Total War.
iLimitedWarRand = 40, so he has a 2.5% chance each turn that he does not consider Total War to start considering a Limited War against anyone who touches 8 of his land tiles with their land tiles.
IDogPileRand = 25, so he has a 4% chance each turn that he does not consider Total War or Limited War to starting considering a DogPile War against anyone who is at war with somebody else and is also touching 8 of his land tiles with their land tiles.

Is that right?
A Land Target for Monty who is at war with a different civ faces around 8.5% chance of being considered for one of Monty's 3 war rolls?
And a non-Land Target faces a 2% chance each turn for Monty's Max War roll only?

Also, how big of a factor is iHighUnitSpendingPercent for modifying iMaxWarRand?
 
Last edited:
Top Bottom