Improving CvPlayerAI::AI_doEnemyUnitData()

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.
 
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.
 
First of all, good job finding the first two things. :)

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 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.
 
Top Bottom