national limit on units ignored?

davidlallen

Deity
Joined
Apr 28, 2008
Messages
4,743
Location
California
A few weeks back I posted a problem where national limits on buildings had a funny result, see this thread. In that case I was able to trace the code and find a solution, but now I have a similar problem for national units and I cannot find the problem in the code.

I have attached a tiny mod in which axemen have a national limit of 3 units, and they have a cost of 1 and AIWeight of 200. This should make the AI tremendously interested in building them.

In the python of the tiny mod, I have created a logfile (c:\stats.csv) which lists when axemen are created and killed. It seems that the national limit is not respected at all by the AI. That is, with a national limit of 3, I see messages that a civ has built 4, without any being killed.

For buildings, there is a place where if the game detects too many national buildings, it randomly deletes one. So the effect is correct, but the hammers spent building the extra illegal building are wasted. For units, it seems that the game is also deleting them; that is, when I scan around, I cannot find all four of the axemen that were built.

Can anybody point me to the code which is deleting a unit, when the national lmit is exceeded? If I can find the code, I can perform a fix similar to what I did for national buildings.

The underlying reason may be that the AI does not respect the national limit when constructing units. Finding and fixing that place would be even better, since when the game silently deletes the unit the hammers are wasted.

This is a problem for Dune Wars, because there is a new unit "Mentat" I am trying to introduce with a national limit of three. It has a complex script which fires in onUnitBuilt that has side effects lasting until a matching onUnitKilled, expecting that only three of these side effects will ever happen at a time for a given civ. But I am seeing dozens of these effects happening at once for a given civ. I can see the onUnitBuilt script called dozens of times, but only a small number of Mentat units are visible on the map, and onUnitKilled is not called enough to explain the difference. So my assumption is that the AI is building too many, and the game is silently deleting them without calling onUnitKilled.
 
CvPlayer::canTrain is what you are looking for. There is also a CvCity::CanTrain function as well, which can also work, in fact I think the CvCity function reference's this function, and is ultimately where the buck stops in terms of if a unit can be trained or not. Once you code a solution please upload the code for the UP, as that way it can get into the UP, betterAI, and RevDCM. Here is the code that is currently hanlding it in CvPlayer:

Code:
bool CvPlayer::canTrain(UnitTypes eUnit, bool bContinue, bool bTestVisible, bool bIgnoreCost) const
{
	PROFILE_FUNC();

	UnitClassTypes eUnitClass;
	int iI;

	eUnitClass = ((UnitClassTypes)(GC.getUnitInfo(eUnit).getUnitClassType()));

	FAssert(GC.getCivilizationInfo(getCivilizationType()).getCivilizationUnits(eUnitClass) == eUnit);
	if (GC.getCivilizationInfo(getCivilizationType()).getCivilizationUnits(eUnitClass) != eUnit)
	{
		return false;
	}
...
	if (GC.getGameINLINE().isUnitClassMaxedOut(eUnitClass))
	{
		return false;
	}

	if (GET_TEAM(getTeam()).isUnitClassMaxedOut(eUnitClass))
	{
		return false;
	}

	if (isUnitClassMaxedOut(eUnitClass))
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (GC.getGameINLINE().isUnitClassMaxedOut(eUnitClass, (GET_TEAM(getTeam()).getUnitClassMaking(eUnitClass) + ((bContinue) ? -1 : 0))))
		{
			return false;
		}

		if (GET_TEAM(getTeam()).isUnitClassMaxedOut(eUnitClass, (GET_TEAM(getTeam()).getUnitClassMaking(eUnitClass) + ((bContinue) ? -1 : 0))))
		{
			return false;
		}

		if (isUnitClassMaxedOut(eUnitClass, (getUnitClassMaking(eUnitClass) + ((bContinue) ? -1 : 0))))
		{
			return false;
		}
...
	}

	return true;
}
 
Thanks. This part does not appear to be causing the problem; at worst it can allow one extra unit beyond the national limit, similar to what happens for buildings. The problem I am seeing appears to be much worse than this. Note that jdog5000 has disagreed with my solution for buildings, or at least, he has pointed out a problem with my solution. Is there a better solution, and is it possible to find the place where the excess units are deleted?
 
I suppose my question is why do you want to tackle it where the unit/building is getting deleted? Why not just fix it at the source; either in CvPlayer::canTrain or CvCity::CanTrain?
 
As far as I can tell, canTrain is working correctly. It checks the number of units existing plus those in the queue. It correctly prevents me from adding any units to the build queue once I reach the limit. Yet, the log messages clearly show more units being built. If I can find the place where the deletions are happening, at least I can put a call to onUnitLost and solve my problem. Or, is it possible there are some places in the AI which commit units to be built, without a call to canTrain succeeding?
 
Back
Top Bottom