1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

AI trade valuation quest

Discussion in 'Civ4 - Strategy & Tips' started by Ghpstage, Dec 20, 2013.

  1. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    Yeah, I think I have serious mental issues...:lol:
    Have been gone through >30 straight hours on a big report and now I am finished, I'm rushing for more work. Looks like I'm more of a mental person.

    Putting that aside, here is my dabble into AI_baseBonusVal(), which is the main and biggest function. That child function is called by AI_BonusVal() just like AI_corporationBonusVal() and AI_BonusVal() is indeed the pillar of the final parent function AI_bonusTradeVal().

    Let's start with CvPlayerAI::AI_baseBonusVal()

    I reproduce the schematic of the function with spoilers...

    It starts off with seeing if there are resources with undefined values
    Spoiler :

    Then it rolls through non obsoleted resources

    Happy and Health resources cases are often simple. It follows the simple rule that each point of happiness of health given by the resource gives 100 points. For example, let imagine gems give in some obscure mod +2 :c5happy:, then the resource is worth 200 points...supposing it hasn't any effects on units, buildings, projects or routes. In regular BTS, both ivory and gold are special cases for touching other parts than just happiness.


    Spoiler :


    It can be divided into six subfunctions where there are in fact four categories (units, buildings, projects and routes).
    Those four subfunctions consider both the existence and situation. Because it is simply in the game, it increases the bonus value. It's rather ugly, but it's like that. (I guess that's to avoid buying the resource in advance and the AI doesn't reevaluate for a while...) And the situation is evidently the availability, the modifiers it bring, the contextual era, etc.

    It attempts to find the first coastal city in the list of coastal cities (by acquirement dates)
    Spoiler :

    A coastal city is defined by MIN_WATER_SIZE_FOR_OCEAN, which is 10 water tiles. Indeed, over 9 tiles define the passage from a fresh water lake to an sea or ocean.
    It basically checks if there is at least one coastal city linked to the capital. If found, the function is stopped there (break).
    Otherwise, while still finding the first connected to capital coastal city, other coastal cities are categorized as unconnectedcoastal cities.


    That function usefulness is rather obscure. It's for the case of no coastal cities connected to the capital were found, but all coastal cities are unconnected.
    Spoiler :

    If such situation happens, it forces the status of coastal city to the unconnected coastal city, which makes me wonder what was the purpose of the first function in the end....


    That regards the values of bonuses affecting UNITS
    Spoiler :


    The first part concerns the value of resources regarding units that simply exist (is defined in XML).
    Code:
    Notice it can be mixing, but that function [B][COLOR="Green"]AI_baseBonusVal()[/COLOR][/B] is entirely rolled for one resource CASE per CASE. 
    When it relates to units unlocked by multiple resources, one of the resource must be the present case.
    1) For units that can be trained with access of TWO or more resources, those units add +50 each for that resource. Let imagine for iron while defiling the XML unit file! :crazyeye:

    2) For units that can be trained with EITHER one or another resource (or a third in some obscure mod as Firaxis created its code for mod's sake, hence the weird flexible functions), then those units add +40 each for that resource. There are only 4 units that can be built by either one or another resource in BTS: Axeman, Spear, Mace and another one I don't know.

    3) Then, it adds to the pool of points the effect of a resource as a modifier on a unit. If I recall, there is none in regular BTS. But it works as *iModifier/10 . Thus, if in some obscure mod, it was 100%, then it's +100/10=10 more points.

    4) Then it goes to the function regarding water units (and hence the use of the two first weird functions about coastal cities). Mustn't be a national unit or world unit. It's a modifier that affects water units one by one. For instance, ironclad needs both iron and coal, thus it gets +50 already. No production modifier by resources with that unit. Then that +50 will undergo a the modifier that goes by the weight of coastal cities.
    In words, it basically says if the number of coastal cities is less than half of empire city count, then the past value of the water unit will start to shrink. It's really logical!
    The modifier is mathematically choosing the smallest number between NumCoastalCities*2 and CityCount then dividing by CityCount. For example if there is 1 coastal city for an empire of 4 cities, then the modifier gets to 1*2/4=0.5, that is 50%. Thus +50 of the iron will get to +25. And if there is no coastal cities, the value of the resource collapse to 0. So getting iron or coal from inland civs is cheaper!


    5) The next situational condition regards water units available but no coastal cities OR those water units are obsoleted or simply other type of units that are obsolete. For units that satisfy those conditions, then the value collapse to 2. Yeah, pretty random value, but it's incredibly cheap.
    Otherwise, if the units can be trained, the modifier goes by 2. For an ironclad, it would go by now to 25*2, returning to the original 50.

    6) Finally, we end with the era condition. Indeed, points to certain resources affected units from older era will decrease as era goes.
    It starts by doing the difference.
    FYI:
    Spoiler :

    Ancient Age: 0
    Classical Age:1
    Medieval Age:2
    Renaissance:3
    Industrial Age:4
    Modern Era:5
    Future Era:6

    If the units is from Ancient Ages and the AI is in the Middles Ages, then the difference in absolute values is 2. And the point pool for that unit just got a negative modifier of Points/DiffOfEra.
    If the unit pertains to the present era in which the AI is, then the modifier is 1.5, thus an additionnal 50%. For our case of the ironclad while the AI is industrial Ages: it's 50*1.5=75.

    And that ends the section bonuses vs units.

    In résumé:

    1) Adds 50 points to units unlocked by more than one resource
    2) Adds 40 points to units unlocked by either one or other resources
    3) Adds the first modifier to the pool of points if the bonus concerned give unit production multiplier
    4) Another modifier, but concerning only water units. If the count of coastal cities is less than the empire city count, then the modifier diminishes the base points pool (either the +50 or +40 from point (1) )
    5) Units that can be trained gets a modifier of 2 while units that can't be trained are now worth as cheap as 2 points.
    6) Era effects on units from older eras.



    That regards the values of bonuses affecting BUILDINGS
    Spoiler :


    Again, it goes through the building list from the XML file about buildings.

    1) For buildings enabled with more than one resource, adds +30

    2) For buildings enabled with either one or another resource, adds +20

    3) The points modifier when the resource gives a production multipler. It's *ProdMultiplier/10 again. Now, there are buildings affected by resources like the walls or the castles.

    4) If the resource provides power to certain buildings, adds +60.

    5) If the resource augments the yield modifier of a building, the it's +Yield/2. Additionally, if the building provides yield modifier from power now, it's +YieldModifierFromPower to the points pool. The IronWorks is the sole case of building having a yield modifier from a resource accessibility (coal and iron).

    6) Now joins the situational conditions not to make future buildings affecting the value of a resource before its time. If build-able, then the points pool for the resource case of a case of a building is doubled. Otherwise, the value collapses. So buildings don't increase their cost of a resource just because it exists.

    7) Impact of a heavy coastal empire on water buildings enabled by a resource. Let imagine a coastal building already having 80 points. The modifier is the number of coastal cities divided by the cityCount/2 is the modifier. Thus if more than 50% of cities are coastal, the modifier is a gain.

    8) The exact same effect from era. Revisit the unit section for the formula. It's the exact same.



    That regards the values of bonuses affecting PROJECTS
    Spoiler :


    1) First points pool is the productionModifier brought by a resource on a project. It adds +ProdModifier/10. Think about copper on Internet or Aluminium on Apollo Project or SS parts.

    2) If the project isn't yet built or simply enabled, another modifier of *2. Otherwise, if not available or gone, the previous value from ProdModifier collapses to 0.

    3) The exact same era dependent effect, but in BTS, it's mostly irrelevant as the projects are in moderns times and the sole next era is future. The diff is 1 and the present points pool for a build and resource divided by one is the same value. Thus, era is irrelevant for base BTS.



    That regards the values of bonuses affecting ROUTES (the improvements)
    Spoiler :


    1) If the bonus enables a type of route, then adds +80. There are only the roads and railroads in BTS. Thus it's +80 for the railroads since it needs coal.

    2) If the type of route is enabled by either one or another resource, then adds +40. If railroads were either enabled by coal or iron, that would fit the +40. Does it?

    3) Let's imagine a mod where there are multiple types of routes enabled by resources (RI has paved roads enabled by stone), for a given resource, older types (it is defined as lower value; railroads are iValue=2 and roads are iValue=1 in the respective XML file) of routes get their value halved while the superior route is remained intact. No era effects here.





    At the very last, the final pool of points from units, buildings, projects and routes are added altogether and divided by a factor 10. That is the final value FOR a GIVEN resource.




    I'll work about the parents functions later. I'm getting sleepy. Hope it helps.
     
  2. Ghpstage

    Ghpstage Deity

    Joined:
    Jan 15, 2009
    Messages:
    2,944
    Location:
    Bristol, England
    Interesting stuff, thanks
    So for our purposes the value of :health: and :) resources bar gold and ivory is 100. Following this through to find the value of these, pre-corps,

    Bonusval is just
    Then the trade value,
    Code:
    int CvPlayerAI::AI_bonusTradeVal(BonusTypes eBonus, PlayerTypes ePlayer, int iChange) const
    {
    	int iValue;
    
    	FAssertMsg(ePlayer != getID(), "shouldn't call this function on ourselves");
    
    	iValue = AI_bonusVal(eBonus, iChange);
    
    	iValue *= ((std::min(getNumCities(), GET_PLAYER(ePlayer).getNumCities()) + 3) * 30);
    	iValue /= 100;
    
    	iValue *= std::max(0, (GC.getBonusInfo(eBonus).getAITradeModifier() + 100));
    	iValue /= 100;
    
    	if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isVassal(getTeam()) && !GET_TEAM(GET_PLAYER(ePlayer).getTeam()).isCapitulated())
    	{
    		iValue /= 2;
    	}
    
    	return (iValue * GC.getDefineINT("PEACE_TREATY_LENGTH"));
    }
    The AI trade modifier is 0 for all cases of these resources, simplified leaves

    (Lowest out of buyers citycount vs sellers citycount) + 3) * 300
    halved if from vassal.


    This seems far too large to me, would the value of the :)/:health: resources be divided by 10 as well? I mean where you mention
    as I would be expecting trade values somewhere around 200-500 for early-mid game due to how easily you can get them in begs. Else we get 3000 points when the min city condition is 10, which would cost 150GPT :eek:, 15GPT would be believable.

    Assuming this is the case then the value of :)/:health: resources in vanilla BTS and that aren't gold or ivory is
    ((Lowest out of buyers citycount vs sellers citycount) + 3) * 30
    Which is a nice simple equation!

    EDIT - I've now tested this in two games and it works nicely.
    At first I couldn't get why Shaka was willing to take 13GPT for clams rather than 19GPT in the gamesave i'll upload, it turns out that if you go to buy a resource and ask "What do you want for this?" and a pure GPT value comes, up it tells you if the AI is in financial trouble or not.

    So with this we can put a value to happiness and health resources (excluding gold and ivory) before corporations come into play, and can situationally use it to determine if an AI is in Financial Trouble. Thats probably the first useful thing to come out of this thread :D. Nice Tachy!
    I'll even go as far as to suggest this will hold true before the buyer has an active corp, but that needs further testing.

    Also value doesn't take account of the extra health and happy from buildings, and all these resources have the same weight making all these resources have exatcly the same value, so yes, Deer for Gems is a fair trade!

    Wouldn't be too suprised if the SGOTM types already knew all this though...

    Another point worth making here is that the value of a resource trade is calculated for a 10 turn deal, and GPT trades are the same, but Tachy already discovered that the deal is sworn for a 19 turns unless an external force cancel the deal like a resource disconnection.
    So my line of thinking here is that when a human begs from an AI they are really getting value * 19, rather than the value * 10 the AI sees. This could be very useful when it comes to gold begs, as it suggest you get at least 1.9 times as much gold per point from a GPT beg than from a standard gold beg. This should be easy to test too using the beg gold mechanics.
    The same fixed tradevalue for a resource may well have an impacts elsewhere, explaining why resource trades in the AIs favour don't seem to contribute to "Fair Trade" diplo points.
    Theres more than 4;
    Gallics, Privateers and all the lategame naval units except Attack Subs

    Wait!?
    At this point I have to question most of what I have done, I thought the valuations woud be made from the buying party rather than the owner, which would make coal or iron cheaper if we were inland? Which would also mean buying resources before you can build the units (i.e. Oil pre combustion) would be cheaper? The latter makes sense if memoery serves, and a quick WB testgame suggested getting techs via WB that enable new units makes it more expensive.
    And continuing, it would mean that coastal civs will pay more them.
    So is it +50 for units enabled by only 1 resource i.e. Swords?
     

    Attached Files:

  3. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    It's possible there are errors in the evaluation of the funtion. 'twas late and I was in critical mental situation bc of work. Anyways, I'll check that later.

    Also, I always had problem with things evaluation when it comes to point of view. I confuse myself.
     
  4. Ghpstage

    Ghpstage Deity

    Joined:
    Jan 15, 2009
    Messages:
    2,944
    Location:
    Bristol, England
    Thats understandable, i've been getting confused with a lot of things like this myself and am going to have to go over a lot of what i've already done to try and root out problems and standardise the terms I use.

    Also, theres a potentially significant abuse, that i'm not sure I should specify in this thread hiding in the tangent I wandered off on :eek:
     
  5. Lennier

    Lennier Emperor

    Joined:
    Mar 10, 2013
    Messages:
    1,238
    Gender:
    Male
    Location:
    Orange County, NY
    My eyes tend to glaze over when looking over code, but there are ten units in stock BTS that can be built by either one or another resource. The seven you're missing are Battleship, Carrier, Destroyer, Missile Cruiser, Stealth Destroyer, Submarine, and Transport each of which can be built with access to either oil or uranium. The CivFanatics Civilopedia also credits jet fighters as being built with either oil or aluminum, but I thought that was oil and aluminum. (I can't ever remember getting that far in a BTS game, so I don't know if that's unit #11 or a typo on this site.) I can see where someone might have lumped all the "modern" ships into one unit in their mind.

    And I don't think either of us are counting the UUs that are based on Axemen, Spear, or Macemen that can also be built with either Copper or Iron.
     
  6. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    My second name is "Abuse". You don't have to hide it from me. I'm all ears and my PM box has sunken a few pms.

    That will probably follow the path of what I have done with tech trades. I have done an applet able to entirely predict when the AI will release it to the world and it has proven to be working. ("We just don't want to trade it just yet!").
     
  7. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    Yeah, I see there are inconsistencies because there are inconsistencies. Now I have slept, I see the blunder.

    The function in question was:


    Code:
    					
    for (iJ = 0; iJ < GC.getNUM_UNIT_PREREQ_OR_BONUSES(); iJ++)
       {
    	if (kLoopUnit.getPrereqOrBonuses(iJ) == eBonus)
            {
             iTempValue += 40;
            }
        }
    
    Code:
    	<Define>
    		<DefineName>NUM_UNIT_PREREQ_OR_BONUSES</DefineName>
    		<iDefineIntVal>4</iDefineIntVal>
    	</Define>
    I just caught the sense of it. The FOR rolls from 0 to 3 (four times) because it simply rolls over that hereunder in the Units XML. It rolls until one resource of <PrereqBonuses> corresponds the Bonus the function is presently evaluating.

    Code:
    Case of Maceman
    <PrereqBonuses>
    				<BonusType>BONUS_COPPER</BonusType>
    				<BonusType>BONUS_IRON</BonusType>
    				<BonusType>NONE</BonusType>
    				<BonusType>NONE</BonusType>
    </PrereqBonuses>
    
    It is just some code mechanics that could've been ignored...


    ==


    P.S. Be careful when including UUs. There aren't classified as independent units. When referring to units, it's about class of units. Like Fast Workers are in the same class as workers. So basically, for the code purpose, it conceptually converts the UU into the default one.

    Code:
    GC.getNumUnitClassInfos()
     
  8. Lennier

    Lennier Emperor

    Joined:
    Mar 10, 2013
    Messages:
    1,238
    Gender:
    Male
    Location:
    Orange County, NY
    See what I get for looking at the doc rather than the code? :lol:

    Sorta implies that the code only adjusts the valuation for units that are copper or iron, not all multi-optional units. And they left room for more. :rolleyes:
     
  9. Ghpstage

    Ghpstage Deity

    Joined:
    Jan 15, 2009
    Messages:
    2,944
    Location:
    Bristol, England
    As AIs being in Financial Trouble is called up in several functions, I though it would be best to explain how it works somewhere,

    CvPlayerAI::AI_isFinancialTrouble
    Spoiler :
    bool CvPlayerAI::AI_isFinancialTrouble() const
    {
    //if (getCommercePercent(COMMERCE_GOLD) > 50)
    {
    int iNetCommerce = 1 + getCommerceRate(COMMERCE_GOLD) + getCommerceRate(COMMERCE_RESEARCH) + std::max(0, getGoldPerTurn());
    int iNetExpenses = calculateInflatedCosts() + std::min(0, getGoldPerTurn());

    int iFundedPercent = (100 * (iNetCommerce - iNetExpenses)) / std::max(1, iNetCommerce);

    int iSafePercent = 40;
    if (AI_avoidScience())
    {
    iSafePercent -= 8;
    }

    if (GET_TEAM(getTeam()).getAnyWarPlanCount(true))
    {
    iSafePercent -= 12;
    }

    if (isCurrentResearchRepeat())
    {
    iSafePercent -= 10;
    }

    if (iFundedPercent < iSafePercent)
    {
    return true;
    }
    }

    return false;
    }
    This asks the percentage of the AIs income/costs. Getting rid of most of the interims the full equation is,
    iFundedpercent = (100 * (1 + gold output + science output - total expenses + GPT rate)) / (1 + gold output + science output + GPT IF positive)

    Then it asks if iFundedPercent is less than a safe value,

    IF iFundedPercent < iSafePercent

    iSafePercent starts at 40,
    IF the AI is in Avoid Science mode then
    iSafePercent -8

    IF AI has a war plan
    iSafePercent -12


    Another less important modification below will only apply in standard BTS when the AI is researching Future Tech...
    IF IF the AI is researching a repeatable tech AI
    iSafePercent -10
     
  10. Ghpstage

    Ghpstage Deity

    Joined:
    Jan 15, 2009
    Messages:
    2,944
    Location:
    Bristol, England
    I've done some testing on tech and map trades, wondering if anyone thinks it woud be best to provide worked examples in the thread, even if just for things that could be useable ingame?
    Also considering doing the corpvalues both as a block as its not too big, as well as on a corp by corp basis for usability.

    Not likely to do much, if anything over the next few days due to lots of :xmascheers:
     
  11. Lennier

    Lennier Emperor

    Joined:
    Mar 10, 2013
    Messages:
    1,238
    Gender:
    Male
    Location:
    Orange County, NY
    I, for one, would appreciate worked examples for useable in-game things.

    Have a Merry Christmans Ghpstage and thanks for doing the code-diving. (Ditto to Tachywaxon.)
     
  12. Ghpstage

    Ghpstage Deity

    Joined:
    Jan 15, 2009
    Messages:
    2,944
    Location:
    Bristol, England
    Thanks and no problem, part of why i'm doing it is to help me learn things about C++

    Anyway, i'm glad I started looking through some older forum games for examples, as I know have an example of the condition where AIs want 110% * of the value of their offer to make a trade NCXXXIV Dubioza's 1200AD save. That will hopefully give some leads as to what causes this.

    In that game I played about in WB so they had resources to sell and tried to buy resources from Freddy Washington and Mehmed, and while it does follow the health/happiness value equation
    (Lowest of eithers city count + 3) * 30
    closely, it requires an extra 10% value, which brings me to the mysterious "ichange" value in AIconsiderOffer

    Trouble is iChange is a common temporary term used in various places but isn't defined in PlayerAI.cpp
    I assume where it comes from is defined amongst the function name
    but the meaning of a lot of this is lost on me
     
  13. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051

    First of all, you can see the default values of those arguments in the header file attached to the C++ file called by the same name.

    Now, it is:
    Code:
    int AI_dealVal(PlayerTypes ePlayer, const CLinkList<TradeData>* pList, bool bIgnoreAnnual = false, int iExtra = 1) const
    IIRC, a CLL is a C/C++ structure of organization of data where there are data and pointers. The pointers make the list of data linked like a bunch of wagons.
    The difference with a CLinkedList vs a simple LinkedList is being the loopy version of the simple from point A to B. C stands for "closed" I think.
    It's basically a structure that runs through the deal items like techs, resources, etc.

    ===========================

    Yes, as I you said and I assumed you meant that, iChange is just a local variable whose extent is not beyond the function. It simply links the argument to some place inside the function, either a formula, some conditional structure or something else. Sometimes, the chosen naming is clear as crystal to show its role, otherwise, it is rather abstruse. It depends of the programmer. I assume iChange means "Time for change!" in AI POV.

    Here, iChange takes 1 as default value, which is probably defined as "not changed". Otherwise, iChange other values are taken from
    CvPlayerAI::AI_considerOffer(PlayerTypes ePlayer, const CLinkList<TradeData>* pTheirList, const CLinkList<TradeData>* pOurList, int iChange)
    That other iChange in the argument, thus it's an iChange as an argument becomes another function's argument.

    There is indeed in AI_considerOffer() a special starting clause about iChange:
    Code:
    if (iChange > -1)
    	{
    		for (pNode = pOurList->head(); pNode; pNode = pOurList->next(pNode))
    		{
    			if (getTradeDenial(ePlayer, pNode->m_data) != NO_DENIAL)
    			{
    				return false;
    			}
    		}
    	}
    The first call of AI_considerOffer() is in AI_doDiplo() [I already worked entirely that function, not need to do it again...]

    And it is linked to AI re-pondering their past deals if fair or not by today's standards...
    after 20 turns.

    It says if the player is human, enters AI_considerOffer() and checks if !AI_considerOffer() while iChange is now -1.

    Thus that bounces into:

    Code:
    	
    if (iChange < 0)
    	{
    		return (iTheirValue * 110 >= iOurValue * 100);
    	}
    And checks the relation you bolded before. It returns the boolean response to the formula. If false, thus the deal is cancelled in AI_doDiplo().

    Code:
    bCancelDeal = [COLOR="Blue"]true[/COLOR]
    iChange is there for reevaluation of past deals.

    ============================

    At last, regarding bIgnoreAnnual, which is a boolean (the starting b comes from Hungarian Notation).

    If we look into AI_dealVal(), bIgnoreAnnual only concerns deals that are in continuous effect like resources, vassals, GPT, etc. Not instantaneous trades like lump sums, techs, etc.

    And the conditional structure using that local variable is:

    Code:
    if (!bIgnoreAnnual)
    Basically, don't ignore what should be checked "annually".

    I haven't checked in depth, but I haven't seen a true case of that variable. Thus, that's unimportant.
     
  14. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    From what I understood, if iChange>-1, then the AI always says "No", which is probably due to DenialTypes.
    If iChange=-1, it goes through the 10% more value from their side and that is related only with 20 turns checks. Thus, the AI will renew past trades only if the value is 10% of the last time...the AI becomes increasingly demanding. :dunno:

    Reading the code did not help me to get better at C++ in the end. ;) EDIT: I edit this because re-reading makes me feel that is presumptuous/boasting. What I exactly meant is the Civ4 code uses repetitively the same structures used like ifs, fors, etc. Occasionnally, you'll see more exotic ones, but one real C++ code is more of a mental gymnastic than Civ4's. Just seeing basic example of C (not even C++) goes beyond the Civ4 code and my capabilities. Of course, if one remains to the base of interest. If going deeper like how works the save, loading, etc., that might be more complex. Nevertheless, who cares about that stuff. Even modders don't care about that.
    And according to true experts like bestsss, civ4 coding is really basic compared to true capabilities of C++.
     
  15. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    Had this moment of revelation when I recalled AI_dealVal() is also called in CvDeal.cpp. I don't have those great SDK tools that give all the calls between the C++ files, thus illuminations come in drops.

    The excerpt of interest:

    Code:
    if (!isPeaceDealBetweenOthers(pFirstList, pSecondList))
    		{
    			if ((pSecondList != NULL) && (pSecondList->getLength() > 0))
    			{
    				iValue = GET_PLAYER(getFirstPlayer()).[B][COLOR="Green"]AI_dealVal([/COLOR][/B]getSecondPlayer(), pSecondList, [COLOR="Blue"]true[/COLOR][B][COLOR="Green"])[/COLOR][/B];
    
    				if ((pFirstList != NULL) && (pFirstList->getLength() > 0))
    				{
    					GET_PLAYER(getFirstPlayer()).AI_changePeacetimeTradeValue(getSecondPlayer(), iValue);
    				}
    				else
    				{
    					GET_PLAYER(getFirstPlayer()).AI_changePeacetimeGrantValue(getSecondPlayer(), iValue);
    				}
    			}
    			if ((pFirstList != NULL) && (pFirstList->getLength() > 0))
    			{
    				iValue = GET_PLAYER(getSecondPlayer()).[B][COLOR="Green"]AI_dealVal[/COLOR][/B](getFirstPlayer(), pFirstList, [COLOR="Blue"]true[/COLOR][B][COLOR="Green"])[/COLOR][/B];
    
    				if ((pSecondList != NULL) && (pSecondList->getLength() > 0))
    				{
    					GET_PLAYER(getSecondPlayer()).AI_changePeacetimeTradeValue(getFirstPlayer(), iValue);
    				}
    				else
    				{
    					GET_PLAYER(getSecondPlayer()).AI_changePeacetimeGrantValue(getFirstPlayer(), iValue);
    				}
    			}
    		}
    It basically presents the coding of fair trades of one shot trades. bIgnoreAnnual is set to true and represents ignoring continuous trades like GPT.
    When going into AI_dealVal() to get the values of objects, because of bIgnoreAnnual set to true, instantaneous fair trades (and conversely traded with worst enemy at the same time) will be calculated as traded resources, GPT, capitulation and vassality are ignored.

    The one concerning continuous trades (because yes they bring fair trades as much diplo hits for traded with WE) is this function:

    Code:
    void CvDeal::doTurn()
    {
    	int iValue;
    
    	if (!isPeaceDeal())
    	{
    		if (getLengthSecondTrades() > 0)
    		{
    			iValue = (GET_PLAYER(getFirstPlayer()).AI_dealVal(getSecondPlayer(), getSecondTrades()) / GC.getDefineINT("PEACE_TREATY_LENGTH"));
    
    			if (getLengthFirstTrades() > 0)
    			{
    				GET_PLAYER(getFirstPlayer()).AI_changePeacetimeTradeValue(getSecondPlayer(), iValue);
    			}
    			else
    			{
    				GET_PLAYER(getFirstPlayer()).AI_changePeacetimeGrantValue(getSecondPlayer(), iValue);
    			}
    		}
    
    		if (getLengthFirstTrades() > 0)
    		{
    			iValue = (GET_PLAYER(getSecondPlayer()).AI_dealVal(getFirstPlayer(), getFirstTrades()) / GC.getDefineINT("PEACE_TREATY_LENGTH"));
    
    			if (getLengthSecondTrades() > 0)
    			{
    				GET_PLAYER(getSecondPlayer()).AI_changePeacetimeTradeValue(getFirstPlayer(), iValue);
    			}
    			else
    			{
    				GET_PLAYER(getSecondPlayer()).AI_changePeacetimeGrantValue(getFirstPlayer(), iValue);
    			}
    		}
    	}
    }
    
    As clearly shown, it's a calculated function done each turn and has much diminished impact compared to instantaneous trades. It's 10 times weaker (AI_dealVal()/PeaceTimeLength).

    I think instantaneous traded aren't counted there because doTurn() is the type of function processed in-between turns.

    That concludes about bIgnoreAnnual as being the local variable for both types of fair trades/WE diplo hits and that wasn't much important as said. But we learnt that continuous trades that favor the AI (or simply gifts for being faster) are 10 times weaker than instantaneous trades.
     
  16. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    Regarding that issue, unless I was wrong on the function, what rules resource trades is AI_doDiplo().

    Here is the excerpt regarding resources only:

    Code:
    if (AI_getContactTimer(((PlayerTypes)iI), CONTACT_TRADE_BONUS) == 0)
    							{
    										if (GC.getGameINLINE().getSorenRandNum(GC.getLeaderHeadInfo(getPersonalityType()).getContactRand(CONTACT_TRADE_BONUS), "AI Diplo Trade Bonus") == 0)
    										{
    											iBestValue = 0;
    											eBestReceiveBonus = NO_BONUS;
    
    											for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
    											{
    												if (GET_PLAYER((PlayerTypes)iI).getNumTradeableBonuses((BonusTypes)iJ) > 1)
    												{
    													if (GET_PLAYER((PlayerTypes)iI).AI_corporationBonusVal((BonusTypes)iJ) == 0)
    													{
    														if (AI_bonusTradeVal(((BonusTypes)iJ), ((PlayerTypes)iI), 1) > 0)
    													{
    														setTradeItem(&item, TRADE_RESOURCES, iJ);
    
    														if (GET_PLAYER((PlayerTypes)iI).canTradeItem(getID(), item, true))
    														{
    															iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Bonus Trading #1"));
    
    															if (iValue > iBestValue)
    															{
    																iBestValue = iValue;
    																eBestReceiveBonus = ((BonusTypes)iJ);
    															}
    														}
    													}
    												}
    											}
    											}
    
    											if (eBestReceiveBonus != NO_BONUS)
    											{
    												iBestValue = 0;
    												eBestGiveBonus = NO_BONUS;
    
    												for (iJ = 0; iJ < GC.getNumBonusInfos(); iJ++)
    												{
    													if (iJ != eBestReceiveBonus)
    													{
    														if (getNumTradeableBonuses((BonusTypes)iJ) > 1)
    														{
    															if (GET_PLAYER((PlayerTypes)iI).AI_bonusTradeVal(((BonusTypes)iJ), getID(), 1) > 0)
    															{
    																setTradeItem(&item, TRADE_RESOURCES, iJ);
    
    																if (canTradeItem(((PlayerTypes)iI), item, true))
    																{
    																	iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "AI Bonus Trading #2"));
    
    																	if (iValue > iBestValue)
    																	{
    																		iBestValue = iValue;
    																		eBestGiveBonus = ((BonusTypes)iJ);
    																	}
    																}
    															}
    														}
    													}
    												}
    
    												if (eBestGiveBonus != NO_BONUS)
    												{
    													if (!(GET_PLAYER((PlayerTypes)iI).isHuman()) || (AI_bonusTradeVal(eBestReceiveBonus, ((PlayerTypes)iI), -1) >= GET_PLAYER((PlayerTypes)iI).AI_bonusTradeVal(eBestGiveBonus, getID(), 1)))
    													{
    														ourList.clear();
    														theirList.clear();
    
    														setTradeItem(&item, TRADE_RESOURCES, eBestGiveBonus);
    														ourList.insertAtEnd(item);
    
    														setTradeItem(&item, TRADE_RESOURCES, eBestReceiveBonus);
    														theirList.insertAtEnd(item);
    
    														if (GET_PLAYER((PlayerTypes)iI).isHuman())
    														{
    															if (!(abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()]))
    															{
    																AI_changeContactTimer(((PlayerTypes)iI), CONTACT_TRADE_BONUS, GC.getLeaderHeadInfo(getPersonalityType()).getContactDelay(CONTACT_TRADE_BONUS));
    																pDiplo = new CvDiploParameters(getID());
    																FAssertMsg(pDiplo != NULL, "pDiplo must be valid");
    																pDiplo->setDiploComment((DiploCommentTypes)GC.getInfoTypeForString("AI_DIPLOCOMMENT_OFFER_DEAL"));
    																pDiplo->setAIContact(true);
    																pDiplo->setOurOfferList(theirList);
    																pDiplo->setTheirOfferList(ourList);
    																gDLL->beginDiplomacy(pDiplo, (PlayerTypes)iI);
    																abContacted[GET_PLAYER((PlayerTypes)iI).getTeam()] = true;
    															}
    														}
    														else
    														{
    															GC.getGameINLINE().implementDeal(getID(), ((PlayerTypes)iI), &ourList, &theirList);
    														}
    													}
    												}
    											}
    										}
    									}
    In a nutshell, once the timer has expired and the RNG gave a meeting between the calling AI to another player (either AI or human), a trade is initiated. Then,a random value is given to each surplus resource and the biggest value wins (i.e. a resource is randomly chosen). Same is done from the receiver party. And then the comparison of values is done via AI_bonusTradeVal() and the receiver (the called for the offering trade) must have a resource which worth is superior or equal of what is offered by the calling AI. From the human perspective, that is the called in the resource offer, we are either getting a fair trade or a losing trade. From an AI perspective (in a AI-AI trade), the called party will either get a fair trade or a losing one, hence the unfair trades we see. I see the losing AI, the receiver, is forced into the trade implementation.
     
  17. Ghpstage

    Ghpstage Deity

    Joined:
    Jan 15, 2009
    Messages:
    2,944
    Location:
    Bristol, England
    After looking at that Tachy, I think i'll be focusing on human-AI trades for now :lol:
    lol.... theres another thing to add to TMITs list of AI cheats.
    As its random we can't even reliably prevent the silliest resource trades...nice

    Going to be busy for the forseeable future so this is going to slow to a crawl, but I will be carrying it on.
    Depending on whether the dealval used is taken from the original trade, or more likely, re-evaluated on a turn by turn basis this could be quite damning for calculating the begs that are available if resource begs have been done, and similarly GPT begs would become potentially unpredictable....

    Also, if we estimate that the diplo value of a resource gift after 10 turns is twice the initial trade value, but as the original dealval is used for the instant trade if you cancel and redo the deal you can get 10 times the initial value over 10 turns while never letting the AI make use of it :lol:


    I think i'm ready to suggest something that, if not mentioned before (though I suspect people have already found), may sound heretical, that is that the existing main reference for begging/demanding "pushing and begging" has a major mistake in it, and that it causes, it to be out by a factor of the square of the power ratio
    Code:
    		iThreshold = (GET_TEAM(getTeam()).AI_getHasMetCounter(GET_PLAYER(ePlayer).getTeam()) + 50);
    
    		iThreshold *= 2;
    
    		if (GET_TEAM(GET_PLAYER(ePlayer).getTeam()).AI_isLandTarget(getTeam()))
    		{
    			iThreshold *= 3;
    With the initial value of 50 + 2 per turn, or 25 + 1 :gold: per turn for short. As the player can generally get 150-200 :gold: every 25-30 turns theres obviously a big multiplier to follow as an increase of just 1 :gold: per turns value just ain't gonna cut it. So looking at the next part we have power scaling,
    whats said in the original thread is
    This is where the mistake must lie.

    Assuming that soldier values are used for power, then the +100 is too small to matter only being there to prevent zeros, and for any practical use can be safely ignored.

    If you take the quoted from the linked thread, then, for high difficulties where for much of the game, a power ratio of 0.2 against an enemy is normal, then you end up with the already pitiful grant value divided by 5....
    If, instead you invert the power ratio you get a sensible equation of 5*1*25 = 125 though for a land target this would be trebled getting awful large.
    It also fits that the eplayer term refers to the one your asking from like everything else.

    This would mean grant values larger the weaker you are, which for Pleased/Friendly begs does kind of make sense, but for tribute demands it seems more than a bit daft :lol:

    Also Tachy, while you've gone through the fair trade diplo bonus, has anyone yet covered its neighbour, the "you traded with our worst enemy" malus?
     
  18. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    I've gone through that just like I've gone though AI_isFinancialTrouble(). :)
    Will see later.
     
  19. Ghpstage

    Ghpstage Deity

    Joined:
    Jan 15, 2009
    Messages:
    2,944
    Location:
    Bristol, England
    Fail lol :sad:
    Probably should read through your entire mechanics thread to remind me whats in it.
     
  20. Manco Capac

    Manco Capac Friday,13 June,I Collapse

    Joined:
    Mar 1, 2010
    Messages:
    8,051
    In fact, I vaguely recall TMIT himself ranting about that once...in some game where he was between two civilizations and he was at war with one. Probably, the one at war with Phil randomly contacted the other side AI for trading something stupid for their iron (since they are coerced into that trade according to the code).


    Looking forward this. I'm rather tired of those repetitive discussions elsewhere about the same things. Some people find comfort there, but my ADHD mind can't bear this. :D

    You nailed it.
    In CvPlayerAI::AI_doTurnPre() is listed the called functions that should be rolled each turn. It's a bunch of functions that change a bunch of abstract aspects of an AI empire (there are other functions following this in the same category as done each turn):



    • [*]AI_invalidateCloseBordersAttitudeCache()
      [*]AI_doCounter()
      [*]AI_updateBonusValue() ==> The one of interest.
      [*]AI_doEnemyUnitData()
      [*]if (isHuman()) { return;}
      [*]AI_doResearch()
      [*]AI_doCommerce()
      [*]AI_doMilitary()
      [*]AI_doCivics()
      [*]AI_doReligion()
      [*]AI_doCheckFinancialTrouble()
      [*]if (isBarbarian()) { return;}
      [*]if (isMinorCiv()) { return;}

    Code:
    void CvPlayerAI::AI_updateBonusValue(BonusTypes eBonus)
    {
    	FAssert(m_aiBonusValue != NULL);
    
    	//reset
        m_aiBonusValue[eBonus] = -1;
    }
    First of all, ignore the other function under the same name with only difference being it has no arguments at all: it's just a bridge between AI_doTurnPre() and the function above in
    Code:
     tags. 
    
    So, it simply resets the value of each bonus to the value -1 and as noted in my past posts, that value is the starting clause of even starting [COLOR="Green"][B]AI_baseBonusValue()[/B][/COLOR]:
    
    [CODE]if(m_aiBonusValue[eBonus] == -1)
    In conclusion, yes, bonuses values are recalculated each turn, making the whole "how strong is exactly resource impact on attitude over time for fair trades and worst enemy attitudes?" a bit messy. But also, it's unnecessary to make prediction as it is a continuous trade where small bits of attitude value are added progressively and once +4 of fair trades reached (simply checks over diplo screen), just cancel the gifts. The importance of predicting an instantaneous trade is to avoid giving too much over +4 OR more important, avoid as much as possible to max out the -4 for worst enemy as the human wants to extract the most benefits of trades.


    I'm unsure of its meaning. Isn't there 10 turns of unbreakable period for any continuous deals?


    Ok, if I understand well, what bothers you are beggings after the first one as the first one has a freebie of 50 universal points (that's how I call the unit of value for everything). Indeed, the next ones will be granted as big as the number of turns since the last beg. Indeed, the value is doubled per default, meaning one turn does equate 1 :gold: under non financial crisis circumstance. Then, the land target clause (sharing 8 border tiles with the AI more usually) will triple the value, meaning 3 universal points per turn and also 3 :gold: per turn. After 30 turns, it's indeed 90 :gold:. Sadly, I have no recollection of how much gold I can get after 30-40 turns, thus I can't say it's between 150-200 :gold:.
    Finally, there is the last multiplier of power ratio. Yes, the denominator is to avoid the dividing by zero. The numerator means no power doesn't equate you can't beg at all. It's gonna be small, but existent. And yes, I strongly believe that those soldier points are the values for getPower() since multiple past calculi with power ratios and soldier counts in demographics have shown what is that getPower(). But it isn't that important as absolute values as power ratio is rather the last multiplier itself (with some minor truncation). If the power ratio is 0.2, you get a fifth of what would be if you were both as powerful.

    I'm confused by the last part where it says you become weaker and gets more. I don't think so by perusing the code. I think you are confusing something. The numerator is the soldier count of the asking player as it fetches the functoin GET_PLAYER, which means "us". Thus, it's our power over theirs. Not the inverse. Otherwise, that would gainsay a lot of functions I saw in the past as much as the game logic.

    Here's the function. I don't think it's necessary I translate this as it is clearly exposed.

    Code:
    nt CvPlayerAI::AI_getRivalTradeAttitude(PlayerTypes ePlayer) const
    {
    	// XXX human only?
    	return -(range(((GET_TEAM(getTeam()).AI_getEnemyPeacetimeGrantValue(GET_PLAYER(ePlayer).getTeam()) + (GET_TEAM(getTeam()).AI_getEnemyPeacetimeTradeValue(GET_PLAYER(ePlayer).getTeam()) / 3)) / ((GET_TEAM(getTeam()).AI_getHasMetCounter(GET_PLAYER(ePlayer).getTeam()) + 1) * 10)), 0, 4));
    }
     

Share This Page