Here is a very basic implementation (more of sketch) of a very rudimentary version of the OP's ideas in LUA. It is anchored to a single integer (in this example--25) that limits the number of units (all units, of all domains, with the exception of DOMAIN_AIR). Any unit a player gets (by whatever means) in excess of that number is automatically destroyed. The only slightly more involved bells & whistles on this concept design is a limitation on the types of units that will be removed if the hard cap is exceeded. I made settlers, workers, traders, and the set from archaeologists to naturalists (including GPs and spies) exempt from the unit cap. So, there can be 50 civilians, but if the 51st unit is a military (non-Air) unit, it will be removed. When I first drafted this, on the quick, I missed your idea about having different caps for different domains, so that's the next item on my agenda. I am writing a few Listener functions to continually collate and update the variables you propose into a single unit cap for each specific Domain (let's see if that's even possible, who knows). I assume all civilian units are exempt from any cap, and so my other task is to segregate the exempt civilians from the rest of the units when determining whether the cap has been exceeded. Finally, I'll tie it all together, and if (or when) I am successful, I'll let you know. In the meantime, here is the fist version of the code, with extensive superfluous print statements peppered throughout

.
Code:
local sAllowedUnitCount = 20
function OnNewPlayerUnitAddedToMap( playerID : number, unitID : number )
if iPlayer == 63 then
print ("A unit has been created. But it appears that the unit is from a Barbarian tribe. Or is it AncientAliens™?")
print ("We have no sway over these uncouth savages. They roam like the wind the vast emptiness of this domain and obey no laws.")
print ("They will be the ruin of us all!")
return
end
local pPlayer = Players[ playerID ]
local pPlayerConfig = PlayerConfigurations[ playerID ]
if pPlayer ~= nil then
print ("A unit has been created.")
print ("We must investigate whether there is cause for concern.")
print ("Our justice shall be swift!")
local iCurrentUnitCount = pPlayer:GetUnits():GetCount()
if iCurrentUnitCount > sAllowedUnitCount then
print ("ACHTUNG! A player has violated the limit - " .. sAllowedUnitCount .. " - on the number of units allowed!")
print ("We must investigate and maintain law and order with extreme prejudice!")
local pPlayerCivName = pPlayerConfig:GetCivilizationTypeName()
print ("Player ID# = " .. playerID .. ", the pernicious " .. pPlayerCivName .. ", has")
print ("exceeded the limit on units! We must prevent overcrowding.")
print ("Determining: must the illegal unit be spared, or can it be removed?")
local pUnit = pPlayer:GetUnits():FindID(unitID)
if pUnit ~= nil then
local pUnitType = pUnit:GetType()
if (pUnitType > 2 and pUnitType < 6) or (pUnitType > 17 and pUnitType ~= 88 and pUnitType ~= 89) then
pPlayer:GetUnits():Destroy(pUnit)
print ("Too many units! " .. pPlayerCivName .. "'s latest unit,")
print ("Unit ID# = " .. unitID .. ", a dastardly " .. GameInfo.Units[pUnitType].UnitType .. ", has been removed.")
else
print ("The " .. pPlayerCivName .. "'s unit count has exceeded this player's allotment")
print ("as a result of a new unit appearing! But the new unit")
print ("(" .. GameInfo.Units[pUnitType].UnitType .. ") is of a type that is protected from removal.")
print ("It pains us, but we must spare it. Continuing to monitor. There is always the next time!")
end
else
print ("Did the unit disappear on its own? Maybe it hates the Carpet of Doom as much as we do.")
print ("Something went wrong it seems. Continuing to monitor with utmost vigilance!")
end
else
print ("False alarm! Everything is in order, but we remain vigilant!")
end
else
print ("A unit has been created. But the owner is unknown to us.")
print ("Must be the Aliens. AncientAliens™")
print ("It's always the Aliens. What if we are all Aliens?")
end
end
Events.UnitAddedToMap.Add(OnNewPlayerUnitAddedToMap);
The code works successfully in the very rudimentary manner described above. Let's see if there is a next step up from there.
NOTE: I immediately see a very basic problem with this process, and it has to do with the so-called "AI". I am not sure there is any easy way to teach the AI this limitation, to make it consider whether building the next unit is a worthwhile investment. Maybe there is something in the XML behaviour/decision trees that can be tweaked to teach the AI to obey the unit cap. But I worry that we will run into a problem where the AI continues building units that continue being destroyed, wasting its time and resources.
Perhaps there is a way to
disable units in the city production panel when the cap is reached, but I am not even sure whether this kind of largely-UI trick would work on the AI that does not use the UI built for human players. Besides, it might involve mixing UI and in game scripts, and that's not possible currently (or ever). Maybe I'll think of something else. We'll see.