Reasons for AI not trading, like WDWTSTTTJY / WFYABTA & the ways to avoid trade blockade.

gavenkoa

Prince
Joined
Jun 11, 2019
Messages
470
Location
Ukraine
In semi-isolation game https://forums.civfanatics.com/threads/nobles-club-366-justinian-i-of-byzantium.692846/ I'm in a situation AI refuses to trade techs because WDWTSTTTJY.

Seems if AI knows only you - it is a degenerate case. I find little info about WDWTSTTTJY and its implications.

Other threads pointed to the function CvTeamAI::AI_techTrade. It mentions following reasons:

Civ4/Assets/XML/Text/CIV4GameTextInfos.xml
Civ4/Assets/XML/Text/CIV4GameText_Misc1.xml

XML:
        <Tag>TXT_KEY_DENIAL_NO_GAIN</Tag>
        <English>"We would have nothing to gain."</English>

        <Tag>TXT_KEY_DENIAL_WORST_ENEMY</Tag>
        <English>"We will never trade with you, our worst enemy!!!"</English>

        <Tag>TXT_KEY_DENIAL_ATTITUDE</Tag>
        <English>"We just don't like you enough."</English>

        <Tag>TXT_KEY_DENIAL_TECH_WHORE</Tag>
        <English>"We fear you are becoming too advanced."</English>

        <Tag>TXT_KEY_DENIAL_TECH_MONOPOLY</Tag>
        <English>"We don't want to start trading away this technology just yet."</English>

        <Tag>TXT_KEY_DENIAL_MYSTERY</Tag>
        <English>"We have our reasons."</English>

        <Tag>TXT_KEY_DENIAL_VICTORY</Tag>
        <English>"We'd rather win the game, thank you very much..."</English>

DLL source code, as pointed in some threads, is in the function:

Spoiler Code for CvTeamAI::AI_techTrade() :

C++:
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;
}


I've got the case of WDWTSTTTJY, in a game I have only 1 AI on the land (espionage allocation supports the idea, as I haven't spoiled the game via WorldBuilder yet), so DENIAL_TECH_MONOPOLY was took place, because iPossibleKnownCount is zero, AI_techTradeKnownPercent() should be 30% for the leader, and AI_getTechMonopolyValue(eTech, eTeam) is non-zero (because all techs open mil units or non-religion buildings or wonders), so iTechTradeKnownPercent > 0 is true ((

Seems AI_getTechMonopolyValue will be zero for few techs, like Alpha, Monotheism, Monarchy, Liberalism, Replaceable Parts (what else are with only religion buildings, no-wonders, no-warriors?).

One AI is a degenerate case, if you want trading - you need to befriend AI, so if you identified semi-isolation you please AI from the beginning... or you won't get +10 relations fast enough (before Astronomy).

Isolation with 2 AIs is less detrimental, iPossibleKnownCount is 1, so we need to overcome condition ((iKnownCount * 100) / iPossibleKnownCount) < iTechTradeKnownPercent = (iKnownCount * 100) < iTechTradeKnownPercent, in other words both AIs should know tech as the condition is for 100% knowledge.

Isolation with 3 AIs even less punishing - iPossibleKnownCount is 2, so the threshold is 50%, which is it for half of the AIs, so if a tech is known by 2 of 3 AIs we won't hit WDWTSTTTJY for many leaders (with 15/20/30/40/50% threshold).

Thus in semi-isolation trade you first fight with WDWTSTTTJY and only then you hit WFYABTA, so breaking isolation has one additional reason (besides overseas large AI cluster trade feast, you miss).
 
Last edited:
Honestly you confuse me gavenkoa..so much effort over simple topics ;)
I did a few more efforts, here:


* Years of peace is +1 once after 60T
* We appreciate the years you have supplied us with resources +1 for 50 turn-resources at most twice.
* Our Open Borders have brought our people close together +1 after 25T twice
* Gifting a city gives at least 1150 trade value, after even 300T it gives almost 1150/300 ~= +4 diplomacy!

Also if you place a gifted city somewhat near AI's capital you could get +1 for liberation - although this info is from vague forum posts - it is the first time I gifted a city and know nothing about liberation bonus...
 
Back
Top Bottom