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

Improving CvPlayerAI::AI_doEnemyUnitData()

Discussion in 'Civ4 - Better AI' started by Maniac, Jul 11, 2010.

  1. Maniac

    Maniac Apolyton Sage

    Joined:
    Nov 27, 2004
    Messages:
    5,588
    Location:
    Gent, Belgium
    I recently had a look at the CvPlayerAI::AI_doEnemyUnitData() function, which led me to spot room for some improvements, and more importantly led me to spot the values it creates don't have any effect on AI behaviour. It's supposed to be used to build useful unitai_counter/reserve/paradrop units, but as point 3 shows, this doesn't work.

    1) First small thing I noticed is line 20261 "else if (pLoopUnit->getOwnerINLINE() != getID())". Wouldn't it be better to change that to "else if (pLoopUnit->getTeam() != getTeam())"? Not much point in calculating the best counter unit for your allies' military.

    2) At the end of the function there's this code:

    Code:
    for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
    	{
    		if (m_aiUnitCombatWeights[iI] > 25)
    		{
    			m_aiUnitCombatWeights[iI] += 2500;
    		}
    		else if (m_aiUnitCombatWeights[iI] > 0)
    		{
    			m_aiUnitCombatWeights[iI] += 1000;
    		}
    	}
    If a rival player has at least one unit of a certain unitcombattype, the value for m_aiUnitCombatWeights will already be over 25. And most/all the time the values for m_aiUnitCombatWeights will be in the hundreds if not thousands. So in effect this code simply adds 2500 to all unitcombatweights. Is this intended?? :confused:

    3) m_aiUnitCombatWeights and m_aiUnitClassWeights are used for the following functions:

    Code:
    int CvPlayerAI::AI_getUnitClassWeight(UnitClassTypes eUnitClass) const
    {
    	return m_aiUnitClassWeights[eUnitClass] / 100;
    }
    
    int CvPlayerAI::AI_getUnitCombatWeight(UnitCombatTypes eUnitCombat) const
    {
    	return m_aiUnitCombatWeights[eUnitCombat] / 100;
    }
    Note the values are divided by 100!

    These values are used in CvPlayerAI::AI_unitValue(...).

    Consider the following snipper of code:

    Code:
    case UNITAI_COUNTER:
    		iValue += (iCombatValue / 2);
    		for (iI = 0; iI < GC.getNumUnitClassInfos(); iI++)
    		{
    			iValue += ((iCombatValue * GC.getUnitInfo(eUnit).getUnitClassAttackModifier(iI) * AI_getUnitClassWeight((UnitClassTypes)iI)) / 7500);
    			iValue += ((iCombatValue * (GC.getUnitInfo(eUnit).getTargetUnitClass(iI) ? 50 : 0)) / 100);
    		}
    		for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
    		{
    //			int iCombatModifier = GC.getUnitInfo(eUnit).getUnitCombatModifier(iI);
    //			iCombatModifier = (iCombatModifier < 40) ? iCombatModifier : (40 + (iCombatModifier - 40) / 2);
    //			iValue += ((iCombatValue * iCombatModifier) / 100);
    			iValue += ((iCombatValue * GC.getUnitInfo(eUnit).getUnitCombatModifier(iI) * AI_getUnitCombatWeight((UnitCombatTypes)iI)) / 10000);
    			iValue += ((iCombatValue * (GC.getUnitInfo(eUnit).getTargetUnitCombat(iI) ? 50 : 0)) / 100);
    		}
    Or more specifically this as an example:

    iValue += ((iCombatValue * GC.getUnitInfo(eUnit).getUnitCombatModifier(iI) * AI_getUnitCombatWeight((UnitCombatTypes)iI)) / 10000);

    Assume GC.getUnitInfo(eUnit).getUnitCombatModifier(iI) is 100 and AI_getUnitCombatWeight((UnitCombatTypes)iI) is 250. That still only results in an insignificant 25000 / 10000 = 2. I'm assuming the code writer forgot that the m_aiUnitCombatWeights value gets divided by 100 already, and as a consequence that in the example line of code the divisor should only be 100.
     
  2. Fuyu

    Fuyu Emperor

    Joined:
    Nov 5, 2009
    Messages:
    1,225
    Location:
    Austria
    1) will only matter if there are team sizes > 1 present but I agree.
    Ad 2)
    Because 2) seems to have happened because there was confusion about how the weights are stored/returned, it should be
    Code:
    for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
    	{
    		if (m_aiUnitCombatWeights[iI] > 25[B]00[/B])
    		{
    			m_aiUnitCombatWeights[iI] += 2500;
    		}
    		else if (m_aiUnitCombatWeights[iI] > 0)
    		{
    			m_aiUnitCombatWeights[iI] += 1000;
    		}
    	}
    - is that what you mean?

    Makes sense.

    3) However there I am unsure, I actually think the / 10000 might be correct.
     
  3. LunarMongoose

    LunarMongoose King

    Joined:
    Jan 29, 2006
    Messages:
    731
    Gender:
    Male
    Location:
    Boston, MA, USA
    First of all, good job finding the first two things. :)

    I agree with Fuyu on this one. In your example you're completely ignoring the first term in the multiplication, iCombatValue, which is a value that can vary widely but will typically be in the 20-110 range. So you would have, perhaps, 50 * 100 * 250 = 1,250,000, or 100 * 50 * 50 = 250,000, which yield 125 and 25 when divided by the vanilla 10,000, which are exactly the kind of values you want.
     
  4. Maniac

    Maniac Apolyton Sage

    Joined:
    Nov 27, 2004
    Messages:
    5,588
    Location:
    Gent, Belgium
    Ah, of course. :-s
     

Share This Page